Sosyal ağ analizi ile belirli bölgelerdeki değerlenebilecek arsaların tespiti -1

Merhabalar,

Yüksek lisansta aldığım sosyal network dersinde gördüklerimi özetleyebileceğim bir çalışma yaptım. Peki neydi bu derste öğrendiklerimiz? Kısa bir özet bilgi sonrasında tekrar konumuza girelim: Tam türkçesi çizge teorisi olan graph theory, Leonhard Euler tarafından 1736 yılında ilk temelleri atılıyor. Genel olarak iki farklı kümenin arasında ilişkileri inceliyor. Kümenin her bir elemanına node(Düğüm) ve bunlar arasındaki ilişkilere de edge olarak tanımlanıyor. Yapılan network analizi sonucunda küme elemanlarının konumunu belirleyen bazı olgular var mesela bunlardan birkaçı degree, closeness ve betwenness vb. dır. Bunların herbirini açıklamak bu yazı için gerçekten uzun olur ama en basitinden bir tanesini açıklamakta fayda var. Açıklaması en kolayı olan degree, küme içinde bir düğüme gelen edge sayısıdır.  İncelemede degree centrality’i kullanacağız. Buna ek olarak closenness’ı analizi anlattığım esnada açıklayacağım.

Şimdide biraz kullanıldığı alanlardan bahsedersem iyi olacak. 🙂 Çok ilginç alanlarda kullanıldığını ve gerçekten yorumlandığında ilginç bilgilerin çıktığını görüyorsunuz. Örneğin CIA tarafından kırmızı bültenle aranan isimleri aktif olarak kullanıldığının hakkında yayınlanan makaleler var (Saddam Hüseyinin yakalanışında kullanılan sosyal network analizini buradan okuyabilirsiniz.) veya Mısırda Arap baharı zamanında sosyal medyadan atılan facebook mesajları ve twitter twitlerini inceleyerek olayları başlatan kişi, kişileri veya ülkeleri ortaya çıkarmaya çalışan network analiz çalışmaları var. (Buradan okuyabilirsiniz) veya bu bahsettiklerimin dışında, gıda sektöründe ürün çıkaran firmaların yeni ürün çıkaracakları zaman farklı ülkelerde kullanılan gıda ürünlerinin içeriklerini sosyal network analizi ile belirleyerek farklı kültürlere göre ürünlerinin insanların damak tadına uygun ürünler çıkarmaya çalışılan makaleler var ve bunun gibi bir çok alan… Bilgi orada duruyor, yeter ki  o yığının içinden istediğimiz veriyi çıkarabilin..

Çok çok kısa bilgilendirmeden sonra konumuza geri dönersek;

Amacımız herhangi bir emlak sitesinden arsa ilanları ve ilan sahiplerinin bilgilerinden oluşan bir model kurmak olacaktır. Model ile ilgili varsayımlarım şunlardır;

  • Bir bölgede ne kadar çok ilan varsa o bölge o kadar popülerdir.
  • Bir satıcı birden fazla bölgelerde satış ilanı verebilir. Eğer bu farklılıklar ne kadar fazla olup ve bir bölgede yoğunlaşırsa bu bölge popüler olmaya adaydır.

Bölgedeki ilan sayısı graph teorisinde degree centrality’e işaret ediyor. Ne kadar çok ilan varsa o kadar edge sayısı olacaktır. Bu demek oluyor ki ilk olarak bakmamız gereken yer degree değerinin yüksek olmasıdır. Bu durum da ilk grup içerisinden eleme yapabilmemizi sağlayacaktır. Gelelim ikinci varsayıma… Bir satıcı birden fazla ilan verip ve birden fazla bölgeyle ilgileniyorsa bu kişinin emlakçı olduğunu gösterir 🙂 birden fazla emlakçının benzer bölgeyle ilgilendikleri bölgelerin kesişim kümesi de popülerliğin başka bir göstergesi olabilir. Ama dediğim gibi aslında bunlar modeli kurmak için varsayımlardır.

İlk olarak herhangi bir emlak sitesinden verilerin çekilebilmesi için gerekli olan Jsoup’un kullanımına;

Siteden verilerin çekilmesi için Java dilinde yazdığım program ile Cytoscape programıyla yapılan analiz, herhalde en az 2 hafta uğraşmışımdır. Lütfen okurken de unutmayın altında yatan emeği 🙂 Site ismini direk olarak vermeyeceğim onun yerine XYZ.com gibi bir notasyon kullanacağim. Hadi bakalım, ilk olarak XYZ.com emlak sitesinden Jsoup kütüphanesini kullanarak nasıl web scraper yapacağınızı anlatacağım. Başlayalım…

Maven projesi kullanıyorsanız aşağıdaki kodları POM’a eklemeniz gerekmektedir. Maven sizin yerinize kütüphaneyi indirecektir.


<dependency>
<!-- jsoup HTML parser library @ http://jsoup.org/ -->
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.2</version>
</dependency>

eğer maven projesi başlatmıyorsanız Jsoup’un sitesine gidip buradan kütüphaneyi bilgisayarınıza indirebilirsiniz. Daha sonrada indirdiğiniz bu kütüphaneyi projenize eklemeniz gerekiyor.

İndirilen tüm bilgileri arraylistte tutabilmek için küçük bir sınıf yazmanız gerekiyor. Ben indirdiğim sitenin adında bir sınıf oluşturmuştum. Bu yazı dizisindeki emlak sitesinin isim notasyonu olarak XYZ olacak tekrar hatırlatmakta fayda var.


import java.text.SimpleDateFormat;
import java.util.Date;

public class XYZ{
private String sahip;
private String mKare;
private String fiyat;
private Date ilanTarihi;
private String ilçe;
private String tamYer;
private int weight;
public XYZ(String sahip, String mKare, String fiyat, Date ilanTarihi, String ilçe, String tamYer) {
super();
this.sahip=sahip;
this.mKare = mKare;
this.fiyat = fiyat;
this.ilanTarihi = ilanTarihi;
this.ilçe = ilçe;
this.tamYer=tamYer;
}

public String getmKare() {
return mKare;
}
public void setmKare(String mKare) {
this.mKare = mKare;
}
public String getFiyat() {
return fiyat;
}
public void setFiyat(String fiyat) {
this.fiyat = fiyat;
}
public Date getIlanTarihi() {
return ilanTarihi;
}
public void setIlanTarihi(Date ilanTarihi) {
this.ilanTarihi = ilanTarihi;
}
public String getIlçe() {
return ilçe;
}
public void setIlçe(String ilçe) {
this.ilçe = ilçe;
}

public String getSahip() {
return sahip;
}

public void setSahip(String sahip) {
this.sahip = sahip;
}

public String getTamYer() {
return tamYer;
}

public void setTamYer(String tamYer) {
this.tamYer = tamYer;
}

@Override
public String toString() {
return "XYZ [Sahibi= "+sahip+" mKare=" + mKare + ", fiyat=" + fiyat + ",
ilanTarihi=" + ilanTarihi.toLocaleString()
+ ", ilçe=" + ilçe + "]";
}

public int getDayThrough(){
SimpleDateFormat format= new SimpleDateFormat("dd.MM.yyyy");
Date now=new Date();

long d1=now.getTime();
long d2=ilanTarihi.getTime();

return (int)Math.abs((d1-d2)/(1000*60*60*24));
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((sahip == null) ? 0 : sahip.hashCode());
result = prime * result + ((tamYer == null) ? 0 : tamYer.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
XYZ other = (XYZ) obj;
if (sahip == null) {
if (other.sahip != null)
return false;
} else if (!sahip.equals(other.sahip))
return false;
if (tamYer == null) {
if (other.tamYer != null)
return false;
} else if (!tamYer.equals(other.tamYer))
return false;
return true;
}

public int getWeight() {
return weight;
}

public void setWeight(int weight) {
this.weight = weight;
}
}

şimdi de asıl koda gelelim. Aşağıdaki kodu çalıştırdığınızda, kod istenilen sayfalardan verileri çekerek “D:\” diskine Result.csv olarak dosyayı kayıt edecek.


import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

import org.jsoup.Connection.Response;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

import domain.XYZ;

public class main {
private static int say=0;

public static void main(String[] args) {
File saveFilePath=new File("D:/result.csv");
ArrayList sahip=new ArrayList<>();
ArrayList sahipWeight=new ArrayList<>();

/*
*Verilen url isimli string parse edilecek adresi
*gösteriyor. Arama parametreleri ise;
*pagingSize gösterilen sayfadaki ilan adetini gösteriyor.
*pagingOffset ise hangi sayfada olduğunuzu gösteriyor.
*/
String url="https://www.XYZ.com/satilik-arsa/kocaeli?pagingOffset=50&amp;amp;amp;pagingSize=50";
try {
for (int a=0;a<951;a=a+50){ if(a>=1)
url="https://www.XYZ.com/satilik-arsa/kocaeli?pagingOffset="+a+"&amp;amp;amp;pagingSize=50";
Response response= (Response) Jsoup.connect(url).timeout(300000).execute();

//Bağlantı sağlanıp döküman parse ediliyor.
Document doc=response.parse();

// a[class='classifiedTitle'] ile DOM elemanı seçilip ilgilideğeri alınıyor.
//Diğer verilerde bu mantıkla yazılmıştır.
Elements detays=doc.select("a[class='classifiedTitle']");
Elements ids=doc.select("tr.searchResultsItem");
Elements mkares=doc.select("td.searchResultsAttributeValue");
Elements fiyat=doc.select("td.searchResultsPriceValue");
Elements dates=doc.select("td.searchResultsDateValue");
Elements locations=doc.select("td.searchResultsLocationValue");
//Herbir ilanın içine girilerek arsanın tam konumu ve ilan sahibinin verileri alınıyor.
for(int i=0;i<dates.size();i++){ String urlDetay="https://www.XYZ.com"+detays.get(i).attr("href"); Response responseDetay= (Response) Jsoup.connect(urlDetay).timeout(300000).execute(); Document docDetay=responseDetay.parse(); Elements sahips=docDetay.select("div[class='username-info-area']"); Elements tamYers=docDetay.select("h2 a"); sahip.add(new XYZ(sahips.get(0).text(), mkares.get(i).text(), fiyat.get(i).text(), fixDate(dates.get(i).text()), locations.get(i).text(), tamYers.get(2).text()) ); } } BufferedWriter writer = new BufferedWriter(new FileWriter(saveFilePath.getAbsolutePath())); writer.write("locations,owner,weight\n"); for (XYZ element : sahip) { sahip.stream().forEach( k->{

if(element.equals(k)){
say++;
}
});;
element.setWeight(say);
if(!sahipWeight.contains(element))
sahipWeight.add(element);
say=0;
}

//Tüm veriler alındıktan sonra yazma işlemine geçiliyor.
for (XYZ element : sahipWeight) {
//writer.write(element.getIlçe()+","+element.getSahip()+","+element.getDayThrough()+"\n");
writer.write(element.getTamYer()+","+element.getSahip()+","+element.getWeight()+"\n");
System.out.println(element.toString());
}

writer.flush();
writer.close();

} catch (IOException | ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

// Ayı rakam olarak ifade edebilmek için bir metot.
private static Date fixDate(String date) throws ParseException{
String[] parseDate=date.split(" ");
String mounth="";
SimpleDateFormat format= new SimpleDateFormat("dd.M.yyyy");
switch (parseDate[1]) {
case "Ocak":
mounth="01";
break;
case "Şubat":
mounth="02";
break;
case "Mart":
mounth="03";
break;
case "Nisan":
mounth="04";
break;
case "Mayıs":
mounth="05";
break;
case "Haziran":
mounth="06";
break;
case "Temmuz":
mounth="07";
break;
case "Ağustos":
mounth="08";
break;
case "Eylül":
mounth="09";
break;
case "Ekim":
mounth="10";
break;
case "Kasım":
mounth="11";
break;
case "Aralık":
mounth="12";
break;

default:
break;
}

return format.parse(parseDate[0]+"."+mounth+"."+parseDate[2]);
}

}

Aslında kodu biraz inceleye bilirseniz, şunu fark edeceksiniz ki aslında arka planda gereksiz çok fazla hesaplanan veri var. Bu veriler hesaplanıyor ancak en son programın çıktısı olan Result.csv dosyasına yazılmıyor. Bunun en büyük sebebi ise ilk başta tam olarak modeli oturtamamdan kaynaklanıyor. Aslında csv dosyasında analizde kullanılan kümeler kocaeli bölgesindeki arsa isimleri, ilan sahiplerinin isimleri ve ilan sahipleri aynı bölgeden kaç kez ilan verdiğidir.

Bu Jsoup hakkında yazdıklarıma ek olarak, hangi DOM elemanını nasıl bulunacağına dair kafanızda soru işaretleri varsa Jsoup sitesindeki Try Jsoup butonuna tıklayarak hangi DOM elemanını seçmeniz gerektiği konusunda sizi yönlendirecektir. (Buradan ulaşabilirsiniz.)

Bir sonraki yazımda kurduğumuz modelin yapısını ve cytoscape’te yapılan analizini inceleyeceğiz. Belki 3. bir yazı olarak da gephi ile bakabiliriz.

Görüşmek üzere
Gökhan

http://www.gokhansaman.com/wp-content/plugins/sociofluid/images/google_48.png http://www.gokhansaman.com/wp-content/plugins/sociofluid/images/myspace_48.png http://www.gokhansaman.com/wp-content/plugins/sociofluid/images/facebook_48.png http://www.gokhansaman.com/wp-content/plugins/sociofluid/images/yahoobuzz_48.png http://www.gokhansaman.com/wp-content/plugins/sociofluid/images/twitter_48.png