Ana içeriğe geç

Metindeki Kelimelerin Mutlak ve Ağırlıklandırılmış Sıklığı

Bu eğitimde, metin madenciliğinde mutlak ve ağırlıklandırılmış kelime sıklığını ve bunu defaultdict ile pandas DataFrame’leri kullanarak nasıl hesaplayacağınızı öğreneceksiniz.
· 15 dk. oku

Yapay Zeka ile Keşfedin

Metin madenciliğinde önemli metrik kümelerinden biri, belirli bir metin dokümanları külliyatındaki kelimelerin (veya herhangi bir token’ın) sıklığıyla ilgilidir. Ancak, her belgenin belgeye ait belirli bir niteliği tanımlayan sayısal bir değerle ilişkilendirildiği durumlarda, ilave metrik kümeleri de kullanabilirsiniz.

Bazı örnekler:

  • Tweet’ler ve bunların aldığı etkileşim sayıları.
  • URL’ler ve sayfa görüntülemeleri ile hemen çıkma sayıları.
  • Film adları ve gişe geliri.
  • Anahtar kelimeler ve gösterimler, tıklamalar, dönüşümler.

Bu eğitimde,

  • Önce, bir belge külliyatında kelimelerin mutlak ve ağırlıklandırılmış geçiş sıklığını hesaplayan ve karşılaştıran basit bir fonksiyon oluşturma sürecinden geçeceksiniz. Bu, bazen ilk on değere bakarak net olmayan gizli eğilimleri ve toplamları ortaya çıkarabilir. Ayrıca çoğu zaman mutlak kelime sıklığından da farklı olabilirler.
  • Ardından, gerçek bir veri kümesini (film adları ve gişe geliri) görecek ve gizli eğilimleri keşfetmeyi umacağız. Küçük bir ipucu: aşk bir şekilde karşımıza çıkacak!
  • Programlama dili olarak Python kullanacak ve işin ağır kısmı için collections modülünün defaultdict veri yapısından, nihai çıktıyı yönetmek için de pandas DataFramelerinden yararlanacaksınız.

Mutlak ve Ağırlıklandırılmış Kelime Sıklığı: Giriş

İki tweet’iniz olduğunu ve içerikleri ile gösterim (görüntüleme) sayılarının aşağıdaki gibi olduğunu varsayalım:

Tweet MetniGörüntüleme
spain800
france200

Basit analizi yapmak ve kelimelerinizin 'france' ve 'spain' arasında 50:50 bölündüğünü bulmak kolaydır. Çoğu durumda elinizde yalnızca bu olur ve sadece kelimelerin mutlak sıklığını ölçebilir, bazı ilişkileri çıkarsamaya çalışabilirsiniz. Bu örnekte ise her belgeye dair bazı verileriniz var.

Burada ağırlıklandırılmış sıklık belirgin şekilde farklıdır ve dağılım 80:20’dir. Başka bir deyişle, tweet’lerinizde 'spain' ve 'france' birer kez görünse de, okuyucularınızın gözünde ilki 800, ikincisi 200 kez görünmüştür. Büyük fark!

defaultdict kullanarak Basit Kelime Sıklığı

Şimdi benzer bir belge kümesi için biraz daha kapsamlı şu örneği ele alalım:

BelgeGörüntüleme
france200
spain180
spain beaches170
france beaches160
spain best beaches160

Şimdi belgeler arasında döngü kuruyor, onları kelimelere ayırıyor ve her kelimenin kaç kez geçtiğini sayıyorsunuz:

 from collections import defaultdict

import pandas as pd

text_list = ['france', 'spain', 'spain beaches', 'france beaches', 'spain best beaches']

word_freq = defaultdict(int)

for text in text_list:
    for word in text.split():
        word_freq[word] += 1

pd.DataFrame.from_dict(word_freq, orient='index') \
.sort_values(0, ascending=False) \
.rename(columns={0: 'abs_freq'})
 abs_freq
spain3
beaches3
france2
best1

Yukarıdaki döngüde ilk satır, text_list üzerinde birer birer gezinir. İkinci satır (her belge için), öğeyi boşluk karakterine göre bölerek (başka bir karakter de olabilirdi ('-', ',', '_', vb.)) kelimeleri arasında döngü yapar.

word_freq[word]’a bir değer atamaya çalıştığınızda iki olası senaryo vardır:

  1. word anahtarı vardır: bu durumda atama yapılır (bir eklenir)
  2. word anahtarı word_freq içinde yoktur; bu durumda defaultdict, ilk tanımlandığında kendisine atanan varsayılan fonksiyonu çağırır; burada bu fonksiyon int’tir.

int çağrıldığında sıfır döndürür. Artık anahtar vardır, değeri sıfırdır ve değerine 1 eklenerek atama yapılmaya hazırdır.

İlk tabloda üst sıradaki kelime 'france' iken, her belgedeki tüm kelimeler sayıldıktan sonra 'spain' ve 'beaches'in birincilikte başa baş olduğunu görüyoruz. Bu, özellikle üzerinde çalıştığınız belge listesi onlarca ya da yüz binlerce öğeden oluştuğunda gizli eğilimleri ortaya çıkarmada önemlidir.

Ağırlıklandırılmış Kelime Sıklığı

Artık külliyattaki her kelimenin geçişlerini saydığınıza göre, ağırlıklandırılmış sıklığı görmek istiyorsunuz. Yani, kelimelerin okuyucularınıza kaç kez göründüğünü, sizin onları kaç kez kullandığınıza kıyasla görmek istiyorsunuz.

İlk tabloda kelimelerin mutlak sıklığı 'spain' ve 'france' arasında eşit dağılmıştı, ancak 'spain' bariz biçimde daha fazla ağırlığa sahipti; çünkü değeri 800 iken 'france' için 200’dü.

Peki ikinci, biraz daha karmaşık tablo için ağırlıklandırılmış kelime sıklığı ne olurdu?

Hadi bulalım!

Yukarıda kullandığınız kodun bir kısmını, bazı eklemelerle yeniden kullanabilirsiniz:

 # default value is now a list with two ints
word_freq = defaultdict(lambda: [0, 0]) 

# the `views` column you had in the first DataFrame
num_list = [200, 180, 170, 160, 160]

# looping is now over both the text and the numbers
for text, num in zip(text_list, num_list): 
    for word in text.split(): 
        # same as before
        word_freq[word][0] += 1 
        # new line, incrementing the numeric value for each word
        word_freq[word][1] += num 

columns = {0: 'abs_freq', 1: 'wtd_freq'}

abs_wtd_df = pd.DataFrame.from_dict(word_freq, orient='index') \
             .rename(columns=columns) \
             .sort_values('wtd_freq', ascending=False) \
             .assign(rel_value=lambda df: df['wtd_freq'] / df['abs_freq']) \
            .round()

abs_wtd_df.style.background_gradient(low=0, high=.7, subset=['rel_value'])
 abs_freqwtd_freqrel_value
spain3510170
beaches3490163
france2360180
best1160160

Bazı gözlemler:

  • 'france' genel olarak en yüksek ifade olmasına rağmen, ağırlıklandırılmış sıklığı dikkate aldığınızda 'spain' ve 'beaches' daha baskın görünüyor.
  • rel_value, her kelimenin geçiş başına değerini elde etmek için yapılan basit bir bölmedir.
  • rel_value’a bakınca, 'france' wtd_freq metriğinde oldukça düşük olsa da, geçiş başına değeri yüksek olduğu için potansiyel barındırdığı görülüyor. Bu, örneğin 'france' kapsamındaki içeriklerinizi artırmayı düşündürebilir.

Ayrıca, toplamın çoğunluğunu kaç kelimenin oluşturduğuna daha iyi bir perspektiften bakmak için her tür sıklığın yüzdelerini ve kümülatif yüzdelerini gösteren bazı diğer metrikleri de eklemek isteyebilirsiniz:

 abs_wtd_df.insert(1, 'abs_perc', value=abs_wtd_df['abs_freq'] / abs_wtd_df['abs_freq'].sum())
abs_wtd_df.insert(2, 'abs_perc_cum', abs_wtd_df['abs_perc'].cumsum())
abs_wtd_df.insert(4, 'wtd_freq_perc', abs_wtd_df['wtd_freq'] / abs_wtd_df['wtd_freq'].sum())
abs_wtd_df.insert(5, 'wtd_freq_perc_cum', abs_wtd_df['wtd_freq_perc'].cumsum())
abs_wtd_df.style.background_gradient(low=0, high=0.8)
 abs_freqabs_percabs_perc_cumwtd_freqwtd_freq_percwtd_freq_perc_cumrel_value
spain30.3333330.3333335100.3355260.335526170
beaches30.3333330.6666674900.3223680.657895163
france20.2222220.8888893600.2368420.894737180
best10.11111111600.1052631160

Daha fazla analiz yapılabilir ve daha fazla veriyle genellikle daha çok sürprizle karşılaşırsınız.

Peki bu, gerçek verilerle gerçek dünyada nasıl görünür?

Film adlarına bakacak, başlıklarda en çok hangi kelimelerin kullanıldığını —yani mutlak sıklığı— ve en çok hangi kelimelerin gelirle ilişkilendirildiğini, yani ağırlıklandırılmış sıklığı göreceksiniz.

Boxoffice Mojo 15.000’den fazla filmi, ilgili gişe geliri ve sıralamalarıyla birlikte listeliyor. requests ve BeautifulSoup kullanarak veriyi kazıyarak başlayın — İsterseniz Boxoffice Mojo’yu burada şimdiden keşfedebilirsiniz:

 
import requests
from bs4 import BeautifulSoup
 final_list = []

for i in range(1, 156):
    if not i%10:
        print(i)
    page = 'http://www.boxofficemojo.com/alltime/domestic.htm?page=' + str(i) + '&p=.htm'
    resp = requests.get(page)
    soup = BeautifulSoup(resp.text, 'lxml')
    # trial and error to get the exact positions
    table_data = [x.text for x in soup.select('tr td')[11:511]]  
    # put every 5 values in a row
    temp_list = [table_data[i:i+5] for i in range(0, len(table_data[:-4]), 5)] 
    for temp in temp_list:
        final_list.append(temp)
10
20
30
40
50
60
70
80
90
100
110
120
130
140
150
boxoffice_df = pd.DataFrame.from_records(final_list)

boxoffice_df.head(10)
 01234
01Star Wars: The Force AwakensBV$936,662,2252015
12AvatarFox$760,507,6252009^
23Black PantherBV$681,084,1092018
34TitanicPar.$659,363,9441997^
45Jurassic WorldUni.$652,270,6252015
56Marvel's The AvengersBV$623,357,9102012
67Star Wars: The Last JediBV$620,181,3822017
78The Dark KnightWB$534,858,4442008^
89Rogue One: A Star Wars StoryBV$532,177,3242016
910Beauty and the Beast (2017)BV$504,014,1652017
boxoffice_df.tail(15)
 01234
1548515486The Dark HoursN/A$4232005
15486154872:22Magn.$4222017
1548715488State ParkAtl$4211988
1548815489The Magician (2010)Reg.$4062010
1548915490SkinlessPPF$4002014
1549015491CinemanovelsMont.$3982014
1549115492Hannah: Buddhism's Untold JourneyKL$3962016
1549215493Apartment 143Magn.$3832012
1549315494The MarshAll.$3362007
1549415495The ChambermaidFM$3152015
1549515496News From Planet MarsKL$3102016
1549615497Trojan WarWB$3091997
1549715498Lou! Journal infimeDistrib.$2872015
1549815499InterventionAll.$2792007
1549915500PlaybackMagn.$2642012

Bazı sayısal değerlerde özel karakterler ($, , ve ^) yer aldığını ve bazı değerlerin aslında N/A olduğunu göreceksiniz. Dolayısıyla bunları dönüştürmeniz gerekir:

na_year_idx =  [i for i, x in enumerate(final_list) if x[4] == 'n/a'] # get the indexes of the 'n/a' values
new_years = [1998, 1999, 1960, 1973]  # got them by checking online

print(*[(i, x) for i, x in enumerate(final_list) if i in na_year_idx], sep='\n')
print('new year values:', new_years)
(8003, ['8004', 'Warner Bros. 75th Anniversary Film Festival', 'WB', '$741,855', 'n/a'])
(8148, ['8149', 'Hum Aapke Dil Mein Rahte Hain', 'Eros', '$668,678', 'n/a'])
(8197, ['8198', 'Purple Moon (Re-issue)', 'Mira.', '$640,945', 'n/a'])
(10469, ['10470', 'Amarcord', 'Jan.', '$125,493', 'n/a'])
new year values: [1998, 1999, 1960, 1973]
for na_year, new_year in zip(na_year_idx, new_years):
    final_list[na_year][4] = new_year
    print(final_list[na_year], new_year)
['8004', 'Warner Bros. 75th Anniversary Film Festival', 'WB', '$741,855', 1998] 1998
['8149', 'Hum Aapke Dil Mein Rahte Hain', 'Eros', '$668,678', 1999] 1999
['8198', 'Purple Moon (Re-issue)', 'Mira.', '$640,945', 1960] 1960
['10470', 'Amarcord', 'Jan.', '$125,493', 1973] 1973

Şimdi listeyi uygun adlarla sütunlarını adlandırıp, istediğiniz veri türlerine dönüştürerek bir pandas DataFrame’ine çeviriyorsunuz.

 import re
regex = '|'.join(['\$', ',', '\^'])

columns = ['rank', 'title', 'studio', 'lifetime_gross', 'year']

boxoffice_df = pd.DataFrame({
    'rank': [int(x[0]) for x in final_list],  # convert ranks to integers
    'title': [x[1] for x in final_list],  # get titles as is
    'studio': [x[2] for x in final_list],  # get studio names as is
    'lifetime_gross': [int(re.sub(regex, '', x[3])) for x in final_list],  # remove special characters and convert to integer
    'year': [int(re.sub(regex, '', str(x[4]))) for x in final_list],  # remove special characters and convert to integer
})
print('rows:', boxoffice_df.shape[0])
print('columns:', boxoffice_df.shape[1])
print('\ndata types:')
print(boxoffice_df.dtypes)
boxoffice_df.head(15)
rows: 15500
columns: 5

data types:
lifetime_gross     int64
rank               int64
studio            object
title             object
year               int64
dtype: object
 lifetime_grossrankstudiotitleyear
09366622251BVStar Wars: The Force Awakens2015
17605076252FoxAvatar2009
26810841093BVBlack Panther2018
36593639444Par.Titanic1997
46522706255Uni.Jurassic World2015
56233579106BVMarvel's The Avengers2012
66201813827BVStar Wars: The Last Jedi2017
75348584448WBThe Dark Knight2008
85321773249BVRogue One: A Star Wars Story2016
950401416510BVBeauty and the Beast (2017)2017
1048629556111BVFinding Dory2016
1147454467712FoxStar Wars: Episode I - The Phantom Menace1999
1246099800713FoxStar Wars1977
1345900586814BVAvengers: Age of Ultron2015
1444813909915WBThe Dark Knight Rises2012

'star' kelimesi, ilk on beş filmden beşinde geçtiği için en üst sıralardadır ve Star Wars serisinin, aralarında birkaçı üst sıralarda yer alan daha fazla filmi olduğunu da biliyorsunuz.

Şimdi geliştirdiğiniz kodu kullanalım ve bu veri kümesinde nasıl çalıştığını görelim. Aşağıdaki kodda yeni bir şey yok; sadece hepsini tek bir fonksiyonda topladınız:

 def word_frequency(text_list, num_list, sep=None):
    word_freq = defaultdict(lambda: [0, 0])

    for text, num in zip(text_list, num_list):
        for word in text.split(sep=sep): 
            word_freq[word][0] += 1 
            word_freq[word][1] += num

    columns = {0: 'abs_freq', 1: 'wtd_freq'}

    abs_wtd_df = (pd.DataFrame.from_dict(word_freq, orient='index')
                 .rename(columns=columns )
                 .sort_values('wtd_freq', ascending=False)
                 .assign(rel_value=lambda df: df['wtd_freq'] / df['abs_freq']).round())

    abs_wtd_df.insert(1, 'abs_perc', value=abs_wtd_df['abs_freq'] / abs_wtd_df['abs_freq'].sum())
    abs_wtd_df.insert(2, 'abs_perc_cum', abs_wtd_df['abs_perc'].cumsum())
    abs_wtd_df.insert(4, 'wtd_freq_perc', abs_wtd_df['wtd_freq'] / abs_wtd_df['wtd_freq'].sum())
    abs_wtd_df.insert(5, 'wtd_freq_perc_cum', abs_wtd_df['wtd_freq_perc'].cumsum())

    return abs_wtd_df
word_frequency(boxoffice_df['title'], boxoffice_df['lifetime_gross']).head()
 abs_freqabs_percabs_perc_cumwtd_freqwtd_freq_percwtd_freq_perc_cumrel_value
The30550.0687470.068747675183424980.0811670.08116722100930.0
the13100.0294790.098227329731008600.0396390.12080625170306.0
of13990.0314820.129709301805924670.0362820.15708721572975.0
and5450.0122640.141973121881138470.0146520.17173922363512.0
21580.0035560.14552990326730580.0108590.18259857168817.0

Şaşırtıcı olmayan şekilde, 'stop word'ler en üstte; bu çoğu belge koleksiyonu için benzerdir. Ayrıca bazıları büyük harfle, bazıları küçük harfle yazıldığı için yinelenmiş durumdalar. Dolayısıyla ilgilenmeniz gereken iki açık konu var:

  1. Tüm stop word’leri kaldırın: Bunu fonksiyona yeni bir parametre ekleyip, kendi stop word listenizi sağlayarak yapabilirsiniz.
  2. Tüm kelimeleri küçük harfe çevirerek yinelenmeyi önleyin

İşte fonksiyonun basit bir güncellemesi (yeni rm_words parametresi ve 6, 7, 8. satırlar):

# words will be expanded
def word_frequency(text_list, num_list, sep=None, rm_words=('the', 'and', 'a')):  
    word_freq = defaultdict(lambda: [0, 0])

    for text, num in zip(text_list, num_list):
        for word in text.split(sep=sep): 
            # This should take care of ignoring the word if it's in the stop words
            if word.lower() in rm_words:  
                continue                  
            # .lower() makes sure we are not duplicating words
            word_freq[word.lower()][0] += 1  
            word_freq[word.lower()][1] += num

    columns = {0: 'abs_freq', 1: 'wtd_freq'}

    abs_wtd_df = (pd.DataFrame.from_dict(word_freq, orient='index')
                 .rename(columns=columns )
                 .sort_values('wtd_freq', ascending=False)
                 .assign(rel_value=lambda df: df['wtd_freq'] / df['abs_freq']).round())

    abs_wtd_df.insert(1, 'abs_perc', value=abs_wtd_df['abs_freq'] / abs_wtd_df['abs_freq'].sum())
    abs_wtd_df.insert(2, 'abs_perc_cum', abs_wtd_df['abs_perc'].cumsum())
    abs_wtd_df.insert(4, 'wtd_freq_perc', abs_wtd_df['wtd_freq'] / abs_wtd_df['wtd_freq'].sum())
    abs_wtd_df.insert(5, 'wtd_freq_perc_cum', abs_wtd_df['wtd_freq_perc'].cumsum())

    abs_wtd_df = abs_wtd_df.reset_index().rename(columns={'index': 'word'})

    return abs_wtd_df
from collections import defaultdict
word_freq_df =  word_frequency(boxoffice_df['title'], 
                               boxoffice_df['lifetime_gross'],
                               rm_words=['of','in', 'to', 'and', 'a', 'the', 
                                         'for', 'on', '&', 'is', 'at', 'it',
                                         'from', 'with'])



word_freq_df.head(15).style.bar(['abs_freq', 'wtd_freq', 'rel_value'],
                                               color='#60DDFF') # E6E9EB

 wordabs_freqabs_percabs_perc_cumwtd_freqwtd_freq_percwtd_freq_perc_cumrel_value
021580.004439450.0044394590326730580.01376340.01376345.71688e+07
1star450.00126440.0057038553746588190.008189530.02195291.19437e+08
2man1950.005479070.011182939670378540.00604470.02799762.03438e+07
3part410.001152010.012334932625797770.004971290.03296897.95751e+07
4movie1170.003287440.015622432160505570.004900390.03786932.74876e+07
53630.001770160.017392531975911930.004872270.04274155.07554e+07
6ii670.001882550.019275130777128830.00468960.04743114.5936e+07
7wars:60.0001685870.019443727574971550.004201680.05163284.59583e+08
8last1330.0037370.023180726702296510.004068710.05570152.00769e+07
9harry270.0007586426113297140.003978960.05968059.67159e+07
10me1400.003933690.02787324593301280.003747360.06342791.75666e+07
11potter100.0002809780.02815423948114270.003649050.06707692.39481e+08
12black710.001994940.030148923723064670.003614760.07069173.34128e+07
13-490.001376790.031525723394848780.003564740.07425644.77446e+07
14story1070.003006460.034532222314375260.003400110.07765652.08546e+07

Aynı DataFrame’e abs_freq’e göre sıralanmış olarak bakalım:

(word_freq_df.sort_values('abs_freq', ascending=False)
 .head(15)
    .style.bar(['abs_freq', 'wtd_freq', 'rel_value'],
               color='#60DDFF'))

 wordabs_freqabs_percabs_perc_cumwtd_freqwtd_freq_percwtd_freq_perc_cumrel_value
26love2110.005928630.06954216042068850.002444380.1113997.60288e+06
2man1950.005479070.027997639670378540.00604470.02799762.03438e+07
24my1910.005366680.061899416295404980.002482980.1064788.53163e+06
15i1680.004720430.039252622034397860.003357450.0810141.31157e+07
021580.004439450.0044394590326730580.01376340.01376345.71688e+07
10me1400.003933690.02787324593301280.003747360.06342791.75666e+07
31life1340.00376510.076482215346477320.002338390.1232971.14526e+07
8last1330.0037370.023180726702296510.004068710.05570152.00769e+07
23you1260.003540320.056532717137588530.002611310.1039951.36013e+07
4movie1170.003287440.015622432160505570.004900390.03786932.74876e+07
14story1070.003006460.034532222314375260.003400110.07765652.08546e+07
33night1040.002922170.081455515239173600.002322040.1279461.46531e+07
19american930.002613090.047850518688541920.002847630.09325912.00952e+07
117girl900.00252880.1516448427716610.001284160.266639.36413e+06
16day870.002444510.041697121641987600.003297660.08431162.48758e+07

Şimdi ikisini karşılaştırmak ve gizli eğilimleri görmek için görselleştirelim:

 import matplotlib.pyplot as plt
plt.figure(figsize=(20,8))
plt.subplot(1, 2, 1)

word_freq_df_abs = word_freq_df.sort_values('abs_freq', ascending=False).reset_index()

plt.barh(range(20),
         list(reversed(word_freq_df_abs['abs_freq'][:20])), color='#288FB7')
for i, word in enumerate(word_freq_df_abs['word'][:20]):
    plt.text(word_freq_df_abs['abs_freq'][i], 20-i-1, 
             s=str(i+1) + '. ' + word + ': '  + str(word_freq_df_abs['abs_freq'][i]),
             ha='right', va='center', fontsize=14, color='white', fontweight='bold')
plt.text(0.4, -1.1, s='Number of times the word was used in a movie title; out of 15500 movies.', fontsize=14)
plt.text(0.4, -1.8, s='Data: boxofficemojo.com Apr. 2018.   Feedback: @eliasdabbas', fontsize=14)


plt.vlines(range(0, 210, 10), -1, 20, colors='gray', alpha=0.1)
plt.hlines(range(0, 20, 2), 0, 210, colors='gray', alpha=0.1)
plt.yticks([])
plt.xticks([])
plt.title('Words Most Used in Movie Titles', fontsize=22, fontweight='bold')

# =============
plt.subplot(1, 2, 2)
# plt.axis('off')
plt.barh(range(20),
         list(reversed(word_freq_df['wtd_freq'][:20])), color='#288FB7')
for i, word in enumerate(word_freq_df['word'][:20]):
    plt.text(word_freq_df['wtd_freq'][i], 20-i-1, 
             s=str(i+1) + '. ' + word + ': ' + '$' + str(round(word_freq_df['wtd_freq'][i] / 1000_000_000, 2)) + 'b',
             ha='right', va='center', fontsize=14, color='white', fontweight='bold')
plt.text(0.4, -1.1, s='Alltime boxoffice revenue of all movies whos title contained the word. (Top word is "2") ', fontsize=14)
plt.text(0.4, -1.8, s='Data collection & methodology: http://bit.ly/word_freq', fontsize=14)

plt.vlines(range(0, 9_500_000_000, 500_000_000), -1, 20, colors='gray', alpha=0.1)
plt.hlines(range(0, 20, 2), 0, 10_000_000_000, colors='gray', alpha=0.1)
plt.xlim((-70_000_000, 9_500_000_000))
plt.yticks([])
plt.xticks([])
plt.title('Words Most Associated With Boxoffice Revenue', fontsize=22, fontweight='bold')
plt.tight_layout(pad=0.01)
plt.show()

words most box office data

Görünüşe göre en azından yapımcıların ve yazarların zihninde aşk her şeye galip geliyor! Tüm film adlarında en çok kullanılan kelime o. Ancak ağırlıklandırılmış sıklık (gişe geliri) söz konusu olduğunda o kadar yukarıda değil.

Başka bir deyişle, tüm film başlıklarına bakarsanız, en çok karşınıza çıkacak kelime 'love' olurdu. Ancak izleyicilerin gözünde en çok hangi kelimenin göründüğünü (metrik olarak toplam gişe gelirini kullanarak) tahmin ederseniz, '2', 'star' ve 'man' en çok görüntülenen ya da en fazla gelirle ilişkilendirilenler olurdu.

Açıklık getirmek gerekirse: bunlar çok basit hesaplamalar. 'love' kelimesinin ağırlıklandırılmış sıklığının 1.604.106.767 olduğunu söylediğinizde, bu yalnızca başlığında 'love' kelimesi geçen tüm filmlerin toplam ömür boyu gişe gelirinin bu tutar olduğu anlamına gelir.

'2' kelimesinin en üstte olması da ilginç. Elbette bu bir kelime değil; ancak film serilerinin ikinci bölümlerinin çok büyük bir toplam oluşturduğunu gösteriyor. Beşinci sıradaki '3' için de aynı durum geçerli. 'part' ve 'ii' ifadelerinin de ilk onda olması bu gerçeği doğruluyor.

'American' ve 'movie' yüksek göreli değere sahip.

Bu fonksiyonda kullanılan stop word’lere dair kısa bir not

Genellikle burada olandan daha kapsamlı bir stop word listesi sağlarsınız; özellikle makaleler veya sosyal medya gönderileriyle uğraşıyorsanız. Örneğin nltk paketi çeşitli dillerde stop word listeleri sağlar; bunlar indirilebilir ve kullanılabilir.

Buradaki kelimeler, üst sıralardaki filmler üzerinde birkaç kontrol yapıldıktan sonra seçildi. Bunların birçoğu genellikle stop word kabul edilir; ancak film adları söz konusu olduğunda bazılarını tutmak mantıklıydı; çünkü fikir verebilirler. Örneğin 'I', 'me', 'you' kelimeleri bazı sosyal dinamiklere işaret edebilir. Bir diğer neden de film adlarının çok kısa ifadeler olması ve onlardan mümkün olduğunca anlam çıkarmaya çalışmamızdır.

Kesinlikle kendi kelime listenizle deneyebilir ve biraz farklı sonuçlar görebilirsiniz.

Orijinal film başlıkları listesine geri döndüğümüzde, en üstteki bazı kelimelerin ilk onda bile yer almadığını görüyoruz ve bu, tam da bu yaklaşımla ortaya çıkarmaya çalıştığımız içgörü türüdür.

boxoffice_df.head(10)
 lifetime_grossrankstudiotitleyear
09366622251BVStar Wars: The Force Awakens2015
17605076252FoxAvatar2009
26810841093BVBlack Panther2018
36593639444Par.Titanic1997
46522706255Uni.Jurassic World2015
56233579106BVMarvel's The Avengers2012
66201813827BVStar Wars: The Last Jedi2017
75348584448WBThe Dark Knight2008
85321773249BVRogue One: A Star Wars Story2016
950401416510BVBeauty and the Beast (2017)2017

Sıradaki mantıklı adım, ilginç olan üst kelimeleri daha fazla keşfetmek olabilir. '2' içeren filmleri filtreleyelim ve görelim:

(boxoffice_df[boxoffice_df['title']                  
              .str
              .contains('2 | 2', case=False)] # spaces used to exclude words like '2010'
              .head(10))
 lifetime_grossrankstudiotitleyear
1544122624716DWShrek 22004
3038981310131BVGuardians of the Galaxy Vol. 22017
3138101121932WBHarry Potter and the Deathly Hallows Part 22011
3537358582536SonySpider-Man 22004
3836806126539Uni.Despicable Me 22013
6431243333165Par.Iron Man 22010
7929232473780LG/SThe Twilight Saga: Breaking Dawn Part 22012
8728172390288LGFThe Hunger Games: Mockingjay - Part 22015
117245852179118BVToy Story 21999
146226164286147NLRush Hour 22001

Üst 'star' filmlerine de bir göz atalım:

boxoffice_df[boxoffice_df['title'].str.contains('star | star', case=False)].head(10)
 lifetime_grossrankstudiotitleyear
09366622251BVStar Wars: The Force Awakens2015
66201813827BVStar Wars: The Last Jedi2017
85321773249BVRogue One: A Star Wars Story2016
1147454467712FoxStar Wars: Episode I - The Phantom Menace1999
1246099800713FoxStar Wars1977
3338027057734FoxStar Wars: Episode III - Revenge of the Sith2005
6531067674066FoxStar Wars: Episode II - Attack of the Clones2002
105257730019106Par.Star Trek2009
140228778661141Par.Star Trek Into Darkness2013
301158848340302Par.Star Trek Beyond2016

Ve son olarak, üst 'man' filmleri:

boxoffice_df[boxoffice_df['title'].str.contains('man | man', case=False)].head(10)
 lifetime_grossrankstudiotitleyear
1842331581219BVPirates of the Caribbean: Dead Man's Chest2006
2240901399423BVIron Man 32013
3537358582536SonySpider-Man 22004
4833653030349SonySpider-Man 32007
5333036019454WBBatman v Superman: Dawn of Justice2016
5931841210160Par.Iron Man2008
6431243333165Par.Iron Man 22010
8229104551883WBMan of Steel2013
176206852432177WBBatman Begins2005
182202853933183SonyThe Amazing Spider-Man 22014

Sonraki Adımlar ve İyileştirmeler

İlk adım olarak daha fazla kelime elde etmeyi deneyebilirsiniz: film adları son derece kısadır ve çoğu zaman kelimelerin gerçek anlamını yansıtmaz. Örneğin, bir vaftiz babası normalde bir çocuğun vaftizine tanıklık eden ve o çocuğa bakmayı taahhüt eden kişidir (ya da belki keyif için öldüren bir mafya babası?!).

Bir sonraki egzersiz, film adına ek olarak daha ayrıntılı açıklamalar elde etmek olabilir. Örneğin:

"Bir bilgisayar korsanı, gizemli isyancılardan gerçekliğinin gerçek doğasını ve denetleyicilerine karşı savaştaki rolünü öğrenir."

bize 'The Matrix'ten çok daha fazlasını anlatır.

Alternatif olarak, analizinizi zenginleştirmek için aşağıdaki yollardan birini de izleyebilirsiniz:

  • Daha iyi istatistiksel analiz: aşırı değerlerin/aykırı değerlerin ele alınması, diğer metriklerin kullanılması.
  • Metin madenciliği: benzer kelimeleri ve konuları bir araya getirme ('happy', 'happiness', 'happily', vb.)
  • Daha ayrıntılı analiz: aynı fonksiyonu farklı yıllar/on yıllar veya belirli yapım stüdyoları için çalıştırma.

Veriyi kendinizin ve diğer verileri de keşfetmek isteyebilirsiniz:

Artık film başlıklarındaki kelime sayımlarını incelediniz, mutlak ve ağırlıklandırılmış sıklık arasındaki farkı ve birini göz ardı etmenin tablonun büyük bir kısmını kaçırmanıza nasıl yol açabileceğini gördünüz. Ayrıca bu yaklaşımın sınırlamalarını gördünüz ve analizinizi nasıl geliştirebileceğinize dair bazı önerileriniz var.

Benzer sayılar içeren herhangi bir metin veri kümesini kolayca analiz etmek için çalıştırabileceğiniz özel bir fonksiyonu oluşturma sürecinden geçtiniz ve bu tür bir veri kümesini anlamanızı nasıl geliştirebileceğini öğrendiniz.

Bunu tweet performansınızı, web sitenizin URL’lerini, Facebook gönderilerinizi veya karşılaşabileceğiniz benzer herhangi bir veri kümesini analiz ederek deneyin.

Kodu depo olarak klonlamak ve kendiniz denemek daha kolay olabilir.

word_frequency fonksiyonu, indirilip çalışmalarınızda/araştırmalarınızda kullanmayı deneyebileceğiniz advertools paketinin bir parçasıdır.

Göz atın ve bana bildirin! @eliasdabbas

Kelime sıklığını nasıl oluşturacağınızı öğrenmek için DataCamp’in Python Sözlükleri Eğitimine ve kelime sıklığı dağılımlarını nasıl çizeceğinizi öğrenmek için Python’da Web Kazıma & NLP eğitimine göz atın.

Konular

İlgili