- Veri Kazıma Nedir?
- Neden Veri Kazırız?
- Veri Kazıma Nasıl Çalışır?
- Veri Kazıma Yöntemleri
- Python ile Veri Kazıma
2. Python ile DunyaHalleri.com’un verisinin kazınması
- Veri Kazıma Stratejisi
- BeautifulSoup ile Kategori Altındaki Haber Linklerinin Toplanması
- Haber Metninin Seçilmesi
- Haber Özetinin Seçilmesi
- Haber Başlığının ve Zamanının Seçilmesi
3. Verinin Analizi ve İçeriye Alınması
- Verinin Görselleştirilmesi ve Analizi
- Haber Metinlerinin Kategorilerine Göre Sınıflandırılması
- Word2Vec ile Modelleme
- TSNE ile Word2Vec Görselleştirilmesi
- TextScatter ile Kategorilerin Derin Analizi
4. Sonuç
5. Kodlar ve Kaynakça
Öncelikle bu çalışma 5.sini düzenlediğimiz “Araştırma ve Geliştirme Odaklı Yapay Zeka Eğitimi” için bir başvuru sorusuydu. Veri kazıma izni için Serdar Kuzuloğlu’na ayrıca teşekkürler.
1. Veri Kazıma Nedir?
Veri kazıma diğer bir adıyla Data Scraping, Web sitelerinden veri çıkarma işlemidir.
Neden Veri Kazırız?
Web üzerinde birçok veri bulunuyor. Veri kazıma’da bu veri toplama işlemini otomatikleştirir. Dağıtık halde olan verileri daha düzgün şekilde sunar. İnternet’ten kazınan verilerle birçok çalışma yapılabilir. Bunların en yaygınlarından biri fiyat karşılaştırmasıdır. Elinizdeki ürünün diğer mağazalardaki satış fiyatına bakarak, fiyat stratejinizi belirleyebilirsiniz.
Veri Kazıma Nasıl Çalışır?
Web scraping işlemlerini kavramak için, öncelikle web sayfalarının metin tabanlı biçimlendirme dilleri ile oluşturulduğunu anlamak önemlidir. (en yaygın olanı HTML’dir.)
Bir biçimlendirme dili, bir web sitesinin içeriğinin yapısını tanımlar. Evrensel bileşenlerin ve işaretleme dillerinin etiketleri bulunduğundan, web kesicilerinin ihtiyaç duyduğu bilgileri almaları çok daha kolay olur.
HTML ile ayrıştırma web scraping yalnızca yarısıdır. Bundan sonra scraper daha sonra gerekli verileri alır ve saklar.[1]
Veri Kazıma Yöntemleri
Veri kazımanın birçok yöntemi vardır. Bunlardan birincisi, gerçek kullanıcı gibi davranan bir bot oluşturup, web sitesinden verinin kazınması, diğeri ise web sitesinin html içeriğinin indirilip, istenilen kısımların ayrıştırılması … bugünkü çalışmada biz html içeriği indirip ayrıştırmayı tercih edeceğiz. Ama kullanıcı girişi, butonlara tıklama gibi kullanıcı işlemleri gerektiren çalışmalarda, bir bot oluşturup işlemleri ona yaptırabiliriz.
Python ile Veri Kazıma
Bugünkü çalışmada Python’un BeautifulSoup adlı kütüphanesinden yararlanacağız. BeautifulSoup, HTML veya XML dosyalarını işlemek için oluşturulmuş güçlü ve hızlı bir kütüphanedir.[2] Bu kütüphane ile öncelikle sayfaların html kodlarını indirip, bu kodları parçalayarak verileri kazıyacağız. Daha önce BeautifulSoup ile hiç veri kazıma çalışması yapmadıysanız lütfen Bu makaleye göz atın.
2. Python ile DunyaHalleri.com’un Verisinin Kazınması
Sitedeki bütün veriye ihtiyacımız var. Öncelikle bir veri kazıma stratejisi belirlemeliyiz.
Veri Kazıma Stratejisi
Veri kazıma stratejisinin bu tip çalışmalar için çok önemli olduğunu düşünüyorum, bir sitedeki bütün veriyi otomatik şekilde kazımak istiyorsak bir plana ihtiyacımız var. Burada kısaca veriyi hangi yollarla nasıl bir Pipeline’da kazıyacağımızı belirlemeliyiz.
Bu çalışmada biz öncelikle bütün kategorilerdeki linkleri toplayacağız. Ardından tek tek bu linklerin içerisine girip, istediğimiz veriyi kazıyacağız. Stratejimizin şemasını da aşağıdaki görselde görebilirsiniz.
BeautifulSoup ile Kategori Altındaki Haber Linklerinin Toplanması
#Kütüphanelerimizi içeriye alalım.#Veri İşlemleri import pandas as pd import numpy as np#Veri Kazıma from bs4 import BeautifulSoup as bs import requests import datetime#Konsol Güzelleştirme from progressbar import * from IPython.display import clear_output
Dunyahalleri.com’un 6 farklı ana kategorisi var, öncelikle bu kategorilere gireceğiz. Ardından sayfa sayfa bütün makalelerin linklerini toplayacağız.
#Kategoriler
sections = ["https://www.dunyahalleri.com/category/haftanin-ozeti/page/",
"https://www.dunyahalleri.com/category/genel-gundem/page/",
"https://www.dunyahalleri.com/category/teknoloji-bilim/page/",
"https://www.dunyahalleri.com/category/internet-girisimler/page/",
"https://www.dunyahalleri.com/category/tasarim-inovasyon/page/",
"https://www.dunyahalleri.com/category/kultur-sanat/page/"]
Şimdi ise for döngüleri ile öncelikle kategorileri, ardından kategorinin içerisindeki sayfaları, ve sayfanın içerisindeki yazı linklerini alacağız. Şemamız şu şekilde olacak;
Not: Sağ tarafta gördüğünüz kısım Google Chrome’da f12 tuşuna basarak açılabiliyor. Bu kısımda Html elementlerinin isimlerini, Xpathlerini görebiliyorsunuz.
urls = []
#Öncelikle bir Kategori seçiyoruz.
for section in sections:
#Kategorinin içerisinde sırayla 100 sayfa gezineceğiz.
for i in range(1,100):
try:
#Öncelikle URL'imizi oluşturuyoruz. Örneğin;
#https://www.dunyahalleri.com/category/kultur-sanat/page/25
newurl = section+str(i)
print(newurl)
#Url'nin içerisindeki bütün html dosyasını indiriyoruz.
html = requests.get(newurl).text
soup = bs(html, "lxml")
#Yukarıdaki şemadada görüldüğü gibi bütün makaleler bu element'in içerisinde yer alıyor.
#Bizde bütün makaleleri buradan tags adında bir değişkene topluyoruz.
tags = soup.findAll("div", class_="row row-eq-height herald-posts")[0]
#Sırayla bütün makalelere girip, href'in içerisindeki linki urls adlı listemize append ediyoruz.
for a in tags.find_all('a', href=True):
urls.append((section.split("/")[4],a['href']))
except IndexError:
break
Ardından topladığım bütün bu linkleri Pandas kütüphanesi yardımıyla bir “DataFrame” objesine dönüştürüp, yine “DataFrame” objesinin bir özelliği olan csv çıktı alma özelliğini kullanarak “urldata.csv” olarak çıktı alıyorum.
urldata = pd.DataFrame(urls)
urldata.columns = ["Kategori","Link"]
urldata.head()
#Bazı linkler çoklamışlar, onlardan kurtulmak için drop_duplicates() #Fonksiyonunu kullanacağım.
urldata = urldata.drop_duplicates()
urldata.to_csv('urldata.csv')
Evet şimdi 2. kısım olan haber içi kazıma kısmına geçiyoruz.
Bu kısımda öncelikle haber metinlerini toplayacağız. Alttaki gif’te element isimlerine nasıl erişebileceğinizi görebilirsiniz, sağdaki panelin açılması için F12’ye basmanız yeterli.
Haber Metninin Seçilmesi
Element ismini belirledikten sonra şu şekilde bir kod ile haber metnini kazıyabilir hale geliyoruz.
#Url içerisindeki html'i indiriyoruz. html = requests.get(url).text soup = bs(html, "lxml")#Belirlediğimiz element'in altındaki bütün p'leri seçiyoruz. body_text = soup.findAll("div", class_="tldr-post-content")[0].findAll('p')#Body_text adındaki metni tek bir string üzerinde topluyoruz. body_text_big = "" for i in body_text: body_text_big = body_text_big +i.text
Haber Özetinin Seçilmesi
Haber özetini bulmak için sayfada F12’deki seçme tuşunu seçtikten sonra gezmeniz yeterli, zaten tldr-post-summary adlı elementin aşağısında, hem haber bilgileri hemde özet bulunuyor.
Şu şekilde bir kod ile haber özetini kazıyabiliriz.
#Url içerisindeki html'i indiriyoruz. html = requests.get(url).text soup = bs(html, "lxml")#Özetin bulunduğu element'in metin kısmını alıyoruz. summarized = soup.find("div", class_="tldr-sumamry").text
Haber Başlığının ve Zamanının Seçilmesi
Aynı şekilde haber başlığını ve zamanı bulmak için de sayfada F12’deki seçme tuşunu seçtikten sonra gezmeniz yeterli.
Kodu da şu şekilde olacak;
#Url içerisindeki html'i indiriyoruz. html = requests.get(url).text soup = bs(html, "lxml")#Başlığı ve zamanı'da element isimlerinden bu şekilde seçip, metinlerini alıyoruz. header = soup.find("h1", class_="entry-title h1").text timestamp = soup.find("span", class_="updated").text
Bütün bu parça parça çekim işlemlerini bitirdikten sonra, kodu tamamlayıp bir fonksiyon haline getirdiğimizde ise şunu elde ediyoruz.
def GetData(url):
try:
#Url içerisindeki html'i indiriyoruz.
html = requests.get(url).text
soup = bs(html, "lxml")
#Belirlediğimiz element'in altındaki bütün p'leri seçiyoruz.
body_text = soup.findAll("div", class_="tldr-post-content")[0].findAll('p')
#Body_text adındaki metni tek bir string üzerinde topluyoruz.
body_text_big = ""
for i in body_text:
body_text_big = body_text_big +i.text
#Başlığı ve zamanı'da element isimlerinden bu şekilde seçip, metinlerini alıyoruz.
header = soup.find("h1", class_="entry-title h1").text
timestamp = soup.find("span", class_="updated").text
#Özetin bulunduğu element'in metin kısmını alıyoruz.
summarized = soup.find("div", class_="tldr-sumamry").text
return ((url,header,body_text_big,summarized,timestamp))
#Link boş ise verilen hata üzerine Boş Data mesajını dönüyor.
except IndexError:
return ("Boş Data")
#Eğer link haftalık özet ise özet kısmı olmadığından oraya haftalık özet yazıp, sonuçlar o şekilde dönüyor.
except AttributeError:
return ((url,header,body_text_big,"Haftalık Özet",timestamp))
Ardından bütün veriyi kazıdıktan sonra bir Dataframe’e kaydedip, analiz için hazır hale getiriyoruz.
#Veri kazıma, Urldatasındaki linkleri tek tek fonksiyon ile çalıştırıp, sonuçları bigdata listesine kaydediyor. bigdata = [] k = 0 for i in urldata.Link: clear_output(wait=True) print(k) bigdata.append(GetData(i)) k = k + 1#Verileri DataFrame olarak kaydetme bigdatax = pd.DataFrame(bigdata) bigdatax.drop([5,6,7],axis=1,inplace=True) bigdatax.drop(bigdatax[bigdatax[0]=="B"].index,axis=0,inplace=True) bigdatax.columns = ["Link","Başlık","Body_text","Summarized_Text","TimeStamp"] bigdatax = bigdatax.loc[bigdatax.Link.drop_duplicates().index] bigdatax.index = range(0,len(bigdatax)) bigdatax.head()
Bütün işlemlerin ardından şöyle bir çıktı elde edeceğiz.
3. Verinin Analizi ve Modellenmesi
Kütüphanelerin İçeri Alınması
Farklı birçok çalışma yapacağımız için bir sürü kütüphane kullanacağız.
#Gerekli Kütüphaneler import pandas as pd import numpy as np import re, io import os, pkgutil, json, urllib from urllib.request import urlopen import warnings warnings.filterwarnings(action = 'ignore') import multiprocessing#Görselleştirme from IPython.display import display,HTML,IFrame import seaborn as sns import matplotlib.pyplot as plt import matplotlib.image as mpimg import matplotlib.cm as cm import base64 %matplotlib inline import plotly.express as px sns.set()#NLP ve Modelleme from collections import Counter import gensim from gensim.models import Word2Vec from nltk.corpus import stopwords from nltk.tokenize import sent_tokenize, word_tokenize from scattertext import CorpusFromPandas, produce_scattertext_explorer import scattertext as st from textblob import TextBlob from sklearn.feature_extraction.text import CountVectorizer from sklearn.decomposition import PCA from sklearn.manifold import TSNE from sklearn.model_selection import train_test_split from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report, accuracy_score, confusion_matrix from pprint import pprint from scipy.stats import rankdata, hmean, norm import spacy
Verinin Hazırlanması
Elimizde Scraper’dan gelen 2 farklı dosya bulunuyor. Birisi Kategori ve Linkleri barındırıyor. Diğeri ise Haber linki, metni, özeti, başlığı ve zamanını barındırıyor. Bu verileri link üzerinden birleştirerek haber metnini kategorisi ile eşleştireceğiz.
# Haber içeriği excel'inin içeri alınması
data = pd.read_excel('DunyaHalleri.xlsx')
data.head()
# Url verisinin içeri alınması
urldata = pd.read_csv('urldata.csv')
urldata.drop('Unnamed: 0',axis=1, inplace=True)
urldata.head()
#Veriler link üzerinden eşleşecekler, Eşleşmeyen linkler için kategori boş olarak gelecek.
data = pd.merge(data, urldata, on='Link', how='left')
data.head()
Verinin işlenmesi
Web sitelerinden veri kazıma yöntemleri ile veri elde ettiğimizde, verimiz de harf olmayan(link,hashtag vs.) birçok karakter olabiliyor. Bunlardan kurtulmamız gerekiyor.
def preprocess(ReviewText): #Verideki <br> taglarını kaldır. ReviewText = ReviewText.str.replace("(<br/>)", "") ReviewText = ReviewText.str.replace('(<a).*(>).*(</a>)', '') ReviewText = ReviewText.str.replace('(&)', '') ReviewText = ReviewText.str.replace('(>)', '') ReviewText = ReviewText.str.replace('(<)', '') ReviewText = ReviewText.str.replace('(\xa0)', ' ') #Verideki Linkleri Kaldır. ReviewText = ReviewText.str.replace(r'http[s]?://(?:[a-z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-f][0-9a-f]))+', ' ') return ReviewTextdata['Body_text'] = preprocess(data['Body_text'])
Verinin Görselleştirilmesi ve Analizi
Verimizi de temizlediğimize göre şimdi bazı analizler yapabiliriz, ilk olarak haber bazlı olarak kelime sayısı, harf sayısı, yoğunluk gibi birkaç değişkene bakacağız. Tabii bunları öncelikle oluşturmamız gerekiyor.
data['yogunlasma'] = data['Body_text'].map(lambda text: TextBlob(text).sentiment.polarity)
data['harf_uzunlugu'] = data['Body_text'].astype(str).apply(len)
data['kelime_sayisi'] = data['Body_text'].apply(lambda x: len(str(x).split()))
Bunları da oluşturduktan sonra Plotly kütüphanesini kullanarak, çeşitli görselleştirmeler yapacağız. Öncelikle verideki kelime sayısı dağılımına bakalım.
fig = px.histogram(data, x="kelime_sayisi", nbins=200, title='Kelime Sayısı')
fig.show()
Ardından, harf sayısı ve yoğunlaşma dağılımlarına bakalım.
fig = px.histogram(data, x="harf_uzunlugu", nbins=200, title='Metin Uzunluğu')
fig.show()
fig = px.histogram(data, x="yogunlasma", nbins=20, title='Metin Yoğunlaşması')
fig.show()
Evet şimdi kategori bazlı olarak kutu grafiği yardımıyla, Metin Yoğunlaşması, Harf Sayıları ve Kelime Sayılarına göz atalım.
fig = px.box(data, x="Kategori",y='yogunlasma', color="Kategori",
title="Kategori bazlı Yogunlasma",
hover_data=["yogunlasma"])
fig.show()
fig = px.box(data, x="Kategori",y='kelime_sayisi', color="Kategori",
title="Kategori bazlı kelime sayısı",
hover_data=["yogunlasma"])
fig.show()
fig = px.box(data, x="Kategori",y='harf_uzunlugu', color="Kategori",
title="Kategori bazlı Harf Sayısı",
hover_data=["yogunlasma"])
fig.show()
Son olarak kelimelerin frekanslarına göz atalım. İlk analizimizi Stopwordsleri kaldırmadan yapacağız.
def get_top_n_words(corpus, n=None): vec = CountVectorizer().fit(corpus) bag_of_words = vec.transform(corpus) sum_words = bag_of_words.sum(axis=0) words_freq = [(word, sum_words[0, idx]) for word, idx in vec.vocabulary_.items()] words_freq =sorted(words_freq, key = lambda x: x[1], reverse=True) return words_freq[:n]common_words = get_top_n_words(data['Body_text'], 25) df1 = pd.DataFrame(common_words, columns = ['kelime' , 'geçiş frekansı']) fig = px.bar(df1, x='kelime', y='geçiş frekansı', hover_data=['kelime', 'geçiş frekansı'], color='geçiş frekansı', title='Stopwordsleri kaldırmadan en çok geçen 25 kelime', height=400) fig.show()
Gördüğünüz gibi listede bir sürü etkisiz kelime(Stopwords) bulunuyor. Şimdi bunları kaldırarak grafiği çizdirelim.
#Buradaki turkce-stop-words.txt dosyasına https://github.com/ncarkaci/tr-preprocessing buradan erişebilirsiniz. stop = stopwords.words('Turkish') with open('turkce-stop-words.txt', encoding='utf-8') as file: stw = file.read() stw = stw.split() stw = [s.lower() for s in stw] stop += stwdef get_top_n_words(corpus, n=None): vec = CountVectorizer(stop_words = stop).fit(corpus) bag_of_words = vec.transform(corpus) sum_words = bag_of_words.sum(axis=0) words_freq = [(word, sum_words[0, idx]) for word, idx in vec.vocabulary_.items()] words_freq =sorted(words_freq, key = lambda x: x[1], reverse=True) return words_freq[:n]common_words = get_top_n_words(data['Body_text'], 25) df2 = pd.DataFrame(common_words, columns = ['kelime' , 'geçiş frekansı']) fig = px.bar(df2, x='kelime', y='geçiş frekansı', hover_data=['kelime', 'geçiş frekansı'], color='geçiş frekansı', title='Stopwordsleri kaldırdıktan sonra en çok geçen 25 kelime', height=400) fig.show()
Evet şimdi ise en çok yan yana gelmiş ikili kelimelere bakalım.
def get_top_n_bigram(corpus, n=None): vec = CountVectorizer(ngram_range=(2, 2), stop_words=stop).fit(corpus) bag_of_words = vec.transform(corpus) sum_words = bag_of_words.sum(axis=0) words_freq = [(word, sum_words[0, idx]) for word, idx in vec.vocabulary_.items()] words_freq =sorted(words_freq, key = lambda x: x[1], reverse=True) return words_freq[:n]common_words = get_top_n_bigram(data['Body_text'], 25) df3 = pd.DataFrame(common_words, columns = ['kelime' , 'geçiş frekansı']) fig = px.bar(df3, x='kelime', y='geçiş frekansı', hover_data=['kelime', 'geçiş frekansı'], color='geçiş frekansı', title='Stopwordsleri kaldırdıktan sonra en çok yan yana gelen ikili kelimeler', height=400) fig.show()
Bu kısımda direkt stopwordsleri kaldırılmış hali üzerinden gittim.
Haber Metinlerinin Kategorilerine Göre Sınıflandırılması
Şimdi ise biraz modelleme yapalım. Elimizdekilere baktığımızda, bizde haber metinleri ve kategorileri bulunuyor. Burada rahatlıkla, haber metinlerini kategorize edecek bir model kurabiliriz. Şimdi bu modellemeyi nasıl yapacağımıza göz atalım.
#Öncelikle text_data adında yeni bir dataframe oluşturup, bunda sadece haber metinleri ve kategorilerini tutuyorum.
text_data = data[['Body_text','Kategori']]
text_data.head()
Burada önemli bir nokta var. Kategoriye göre haber sayıları eşit olmadığı için veri setimiz dengesiz halde oluyor. O yüzden bunu dengeli hale getireceğiz.
ax = sns.barplot(data.Kategori.value_counts().index, y=data.Kategori.value_counts(), data=data, palette="rainbow")
print("Data'nın Bölünmeden Önceki Boyutu", len(text_data))
data_tekno = text_data[text_data.Kategori == 'teknoloji-bilim']
data_internet = text_data[text_data.Kategori == 'internet-girisimler']
data_inovasyon = text_data[text_data.Kategori == 'tasarim-inovasyon']
data_genel_gundem = text_data[text_data.Kategori == 'genel-gundem']
data_kultur_sanat = text_data[text_data.Kategori == 'kultur-sanat']
data_hafta = text_data[text_data.Kategori == 'haftanin-ozeti']
text_data = pd.concat([data_tekno.sample(len(data_kultur_sanat), random_state=39), data_internet.sample(len(data_kultur_sanat), random_state=39), data_inovasyon.sample(len(data_kultur_sanat), random_state=39), data_genel_gundem.sample(len(data_kultur_sanat), random_state=39) ,data_kultur_sanat,data_hafta])
print("Data'nın Yeni Boyutu: ", len(text_data))
Verisetimizi dengeli hale getirdikten sonra, haber metni değişkenimiz temiz olduğu için ekstra bir işlem yapmayacağım. Burada direkt TF-IDF yöntemini kullanarak metin verisetimizi modellemeye hazır hale getireceğim. TF-IDF’in ne olduğu hakkında bir fikriniz yok ise şu makaleye göz atabilirsiniz.
#Öncelikle TF-IDF algoritmasını fit etmek için bütün metinleri kapsayan bir corpus oluşturuyoruz.
corpus = []
for i in range(len(data)):
corpus.append(text_data.iloc[i,0])
Corpus’u oluşturduktan sonra TF-IDF’i fit edip ardından bütün verimi de fit ettiğim TF-IDF modeline göre değiştirip verimi hazır hale getireceğim.
# Corpus ile TF-IDF modelini fit ediyoruz.
vectorizer = TfidfVectorizer()
vectorizer.fit(corpus)
Evet şimdi bütün verisetimi modele göre güncelleyip, train ve test olmak üzere 2’ye ayıracağım.
#Burada transform ediyorum. X = vectorizer.transform(corpus).toarray() y = text_data.Kategori#Burada %25-%75 olmak üzere 2'ye ayırıyorum. Stratify=y'de train ve testteki y oranının aynı olmasını sağlıyor. X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25, random_state=39, stratify=y)
Evet şimdide RandomForest algoritmasıyla çoklu sınıflandırma problemine çözüm üreteceğiz.
rf = RandomForestClassifier(class_weight='balanced_subsample') rf.fit(X_train,y_train) y_pred_rf = rf.predict(X_test)print(classification_report(y_test, y_pred_rf)) print(accuracy_score(y_test,y_pred_rf)) cm = confusion_matrix(y_test, y_pred_rf) print(cm)
Çıktı olarak şöyle bir çıktıyla karşılaşıyoruz.
Burada baktığımızda ortalama %50 ile tahminleme yapılabiliyor. Ve sanırım haftanin-ozeti’ni diğerlerinden ayıran belirleyici bir özellik var, yazınının ilerleyen kısımlarında bu özelliklere derinden bakacağız. RandomForest algoritmasını importance score adında, hangi değişkenin modellemede önemli olduğunu belirten bir çıktı veriyor. Şimdi bizde bunu kullanıp, hangi kelimelerin modellemede bizim için önemli olduğuna bakalım.
questions = pd.DataFrame({'features': vectorizer.get_feature_names(),'importance': rf.feature_importances_})
questions = questions.sort_values(by='importance', ascending=False)
questions.head(50)
Bütün bu modelleme işlemlerinin ardından, elimizdeki bütün metin verisini kullanarak birde Word2Vec Modellemesi yapıp, bazı anahtar kelimeler için ağımızı TSNE algoritması ile görselleştirelim.
Word2Vec Modellemesi
Word2Vec , kelimeleri vektör uzayında ifade etmeye çalışan unsupervised (no labels) ve tahmin temelli(prediction-based) bir modeldir .[8] Daha fazla bilgiye şu makaleden ulaşabilirsiniz. Evet şimdi öncelikle metinleri büyük bir string üzerinde toplayıp, bunları kelime kelime parçalayacağız.
#Haber Metinlerini Büyük Bir String üzerinde toplayalım. big = " " for text in data.Body_text: big = big + text#Şimdide bu string'i parçalayalım edelim. big_data = [] for i in sent_tokenize(big): temp = [] # tokenize the sentence into words for j in word_tokenize(i): temp.append(j.lower()) big_data.append(temp)
Şimdi verimiz hazır olduğuna göre Gensim kütüphanesinden yararlanarak, 300 değişkenli bir Word2Vec modeli ortaya çıkartacağız.
model = Word2Vec(big_data, size=300, window=5, min_count=5, workers=multiprocessing.cpu_count())
Evet modelimizi ortaya çıkardık, şimdi belirli anahtar kelimeler için TSNE kullanarak etrafındaki kelimeleri görselleştirelim.
TSNE ile Word2Vec Görselleştirmesi
Manifold learning algoritmaları, asıl olarak veri görselleştirme için kullanılır. t-SNE (t-Distributed Stochastic Neighbor Embedding), en kullanışlı manifold learning algoritmalarından biridir. t-SNE algoritmasının ana fikri, noktalar arasındaki uzaklıkları olabildiğince koruyacak bir şekilde düşük boyutlu bir temsil bulmaktır. t-SNE, her bir veri noktası için rastgele bir düşük boyutlu temsil ile başlar ve, orijinal uzayda yakın olan noktaları birbirine yakın, uzak olanları ise birbirinden uzak tutmaya çalışır. t-SNE, birbirine uzak noktaların arasındaki uzaklığı korumaktansa birbirine yakın noktalara daha çok önem verir. [6]
Evet şimdi Word2vec modelimizi kurduktan sonra belirlediğimiz anahtar kelimeler için TSNE algoritmasını kullanarak etrafındaki kelimeleri görselleştirelim.
keys = ['teknoloji','bilişim','finans','dünya','yapay','blockchain','abd','google','facebook','apple']embedding_clusters = [] word_clusters = [] for word in keys: embeddings = [] words = [] for similar_word, _ in model.most_similar(word, topn=30): words.append(similar_word) embeddings.append(model[similar_word]) embedding_clusters.append(embeddings) word_clusters.append(words)tsne_model_en_2d = TSNE(perplexity=15, n_components=2, init='pca', n_iter=3500, random_state=32) embedding_clusters = np.array(embedding_clusters) n, m, k = embedding_clusters.shape embeddings_en_2d = np.array(tsne_model_en_2d.fit_transform(embedding_clusters.reshape(n * m, k))).reshape(n, m, 2)
Bizim için önemli kelimeleri belirledik, şimdi bunları görselleştirelim.
def tsne_plot_similar_words(labels, embedding_clusters, word_clusters, a=0.7): plt.figure(figsize=(20, 12)) colors = cm.rainbow(np.linspace(0, 1, len(labels))) for label, embeddings, words, color in zip(labels, embedding_clusters, word_clusters, colors): x = embeddings[:,0] y = embeddings[:,1] plt.scatter(x, y, c=color, alpha=a, label=label) for i, word in enumerate(words): plt.annotate(word, alpha=0.5, xy=(x[i], y[i]), xytext=(5, 2), textcoords='offset points', ha='right', va='bottom', size=8) plt.legend(loc=4) plt.grid(True) plt.show()tsne_plot_similar_words(keys, embeddings_en_2d, word_clusters)
TextScatter ile Kategorilerin Derin Analizi
Evet Kategori modellemesinde bahsettiğim Derin analiz kısmında TextScatter adlı kütüphaneden yararlanacağız. TextScatter, hangi kelimelerin ve ifadelerin bir kategori için karakteristik olduğunu görselleştirmeyi amaçlayan bir araçtır.
#Kurmak için;
pip install scattertext
Bu kısımda da yine Modellemede kullandığımız Text_data’yı kullanacağız. Öncelikle “parsed” adında bir değişken oluşturacağız. Bu değişkenin içerisinde Haber metinlerinin kelime kelime parçalanmış hali olacak.
Not: Aşağıdaki kodun çalışması için Spacy’nin modellerini indirmiş olmanız gerekiyor. Şuraya tıklayarak kuruluma bakabilirsiniz.
#Spacy'nin türkçe modeli olmadığı için parçalayıcı olarak ingilizce modelini kullanıyorum.
nlp = spacy.load('en_core_web_sm')
text_data['parsed'] = text_data.Body_text.apply(nlp)
Evet “Parsed” adlı değişkenimizi oluşturduk, şimdi ise parçalanan metinlerden Corpus’umuzu oluşturacağız.
corpus = st.CorpusFromParsedDocuments(text_data, category_col='Kategori', parsed_col='parsed').build()
Evet şimdi ise ilk örneğimizi modellemede karşımıza çıkan haftanın özeti kategorisinde yapalım.
#Category: Bu kısıma derin analizini yapmak istediğimiz kategoriyi yazıyoruz. #not_category_name: Buraya diğer kategorileri yazıyoruz. #minimum_term_frequency: Kelimeler için en az kaç gere corpus'ta geçtiğini yazıyoruz. NOT: 5-10 Gibi sayıları yazarsanız çok büyük olacağından bilgisiyarınız açmayabilir.html = produce_scattertext_explorer(corpus, category='haftanin-ozeti', category_name='Haftanın Özeti', not_category_name=['kultur-sanat','genel-gundem','teknoloji-bilim','internet-girisimler', 'tasarim-inovasyon'], width_in_pixels=1000, minimum_term_frequency=100, transform=st.Scalers.percentile, metadata=text_data['Kategori']) file_name = 'haftanin-ozeti-100.html' #Kaydetmek istediğimiz dosya ismi open(file_name, 'wb').write(html.encode('utf-8')) IFrame(src=file_name, width = 1200, height=700) #Dosyayı Jupyter-Notebook'ta Göstermek için kullanıyoruz.
Bu kodun çıktısı olarak şöyle bir görüntü gelecek;
Siyah Kutuyla işaretlediğim kısım bu kategori için karakteristiği belirleyen kelimeleri kapsıyor.
Bunun dışında bir Filename kısmında belirttiğiniz isimde bir Html dosyası kodları yazdığınız dizinde olacaktır. Onu açtığınızda da şu şekilde bir görüntü karşınıza gelecek;
Aynı zamanda Search for term kısmına herhangi bir kelime yazdığınızda onun nerelerde geçtiğini ve o metnin kategorisini de gösteriyor.
Şimdi birde bu işlemi internet-girişimler kategorisi için yapalım.
html = produce_scattertext_explorer(corpus,
category='internet-girisimler',
category_name='İnternet Girişimler',
not_category_name=['kultur-sanat','genel-gundem','haftanin-ozeti','teknoloji-bilim',
'tasarim-inovasyon'],
width_in_pixels=1000,
minimum_term_frequency=100,
transform=st.Scalers.percentile,
metadata=data['Kategori'])
file_name = 'internet-girisimler-100.html'
open(file_name, 'wb').write(html.encode('utf-8'))
IFrame(src=file_name, width = 1200, height=700)
Ve çıktımızda şu şekilde oluyor; Karakteristiği belirleyen kelimeler sağ tarafta yer alıyor.
4. Sonuç
Bu çalışmada öncelikle Veri Kazımanın ne olduğundan, nasıl ve neden yapıldığından bahsedip, dunyahalleri.com için bir veri kazıma algoritması geliştirdik. Ardından elde ettiğimiz verileri ilk önce Kelime Sayısı, Metin uzunluğu, Metin yoğunluğu, en çok geçen kelimeler, en çok geçen ikililer gibi değişkenler üzerinden analiz ettik. Ardından Haber Metinlerini kategorileri üzerinden RandomForest ile sınıflandırdık. Sonrasında bütün haber metinlerini Word2Vec ile modelledik ve TSNE ile belli anahtar kelimeler için görselleştirmeler yaptık. Son olarakta TextScatter kütüphanesini kullanarak kategori bazlı derin ve detaylı kelime analizi yaptık.
Buraya kadar okuduğunuz için çok teşekkürler, merak ettiklerinizi yorumlarda yazmayı unutmayın. Kendinize iyi bakın, görüşmek üzere 🙂
Kaynakça
[1] Web Scraping nedir? (Nasıl çalışır ve neden önemlidir?)
[2] Python BeautifulSoup Modülü
[3] A Complete Exploratory Data Analysis and Visualization for Text Data
[4] Text Data Visualization in Python
[5] Google News and Leo Tolstoy: visualizing Word2Vec word embeddings using t-SNE
[6] t-SNE ile Manifold Learning
[7] Scattertext: a Browser-Based Tool for Visualizing how Corpora Differ
[8] Word2Vec Nedir ?