मुख्य सामग्री पर जाएँ

पाठ में शब्दों की निरपेक्ष और वेटेड आवृत्ति

इस ट्यूटोरियल में, आप टेक्स्ट माइनिंग में निरपेक्ष और वेटेड शब्द आवृत्ति के बारे में जानेंगे और defaultdict तथा pandas DataFrames के साथ इसे कैसे गणना करें, यह सीखेंगे।
· 15 मि॰ पढ़ें

AI के साथ खोजें

टेक्स्ट माइनिंग में एक महत्वपूर्ण मीट्रिक-समूह, किसी कॉर्पस (दस्तावेज़-संग्रह) में शब्दों (या किसी भी टोकन) की आवृत्ति से संबंधित होता है। हालांकि, ऐसे मामलों में जहाँ हर दस्तावेज़ के साथ उसके किसी गुण का संख्यात्मक मान जुड़ा होता है, आप अतिरिक्त मीट्रिक-समूह का भी उपयोग कर सकते हैं।

कुछ उदाहरण:

  • ट्वीट्स और उनके संबंधित एंगेजमेंट्स की संख्या।
  • URLs तथा उनके पेजव्यूज़ और बाउंस।
  • फ़िल्मों के शीर्षक और उनकी ग्रॉस रेवेन्यू।
  • कीवर्ड्स तथा उनके इम्प्रेशन्स, क्लिक और कन्वर्ज़न।

इस ट्यूटोरियल में,

  • आप पहले एक सरल फ़ंक्शन बनाने की प्रक्रिया से गुजरेंगे, जो दस्तावेज़ों के कॉर्पस में शब्दों की परिमाणात्मक और वेटेड उपस्थिति की गणना और तुलना करता है। यह कभी-कभी ऐसे छिपे रुझान और समेकन उजागर कर सकता है जो केवल शीर्ष दस या इतने मान देखकर स्पष्ट नहीं होते। ये अक्सर परिमाणात्मक शब्द-आवृत्ति से भी अलग हो सकते हैं।
  • इसके बाद, आप वास्तविक जीवन के एक डेटा सेट (फ़िल्म शीर्षक और उनकी ग्रॉस रेवेन्यू) को देखेंगे और उम्मीद करेंगे कि छिपे रुझान मिलें। एक टीज़र: प्यार किसी न किसी तरह सामने आएगा!
  • आप प्रोग्रामिंग भाषा के रूप में Python का उपयोग करेंगे, भारी काम के लिए collections मॉड्यूल की defaultdict डेटा संरचना, और अंतिम आउटपुट के प्रबंधन के लिए pandas के DataFrame का उपयोग करेंगे।

परिमाणात्मक और वेटेड शब्द-आवृत्ति: परिचय

मान लीजिए आपके पास दो ट्वीट हैं और उनका कंटेंट तथा इम्प्रेशन्स (व्यूज़) की संख्या इस प्रकार है:

ट्वीट टेक्स्टव्यूज़
spain800
france200

मूल विश्लेषण करना आसान है और आप पाएंगे कि आपके शब्द 'france' और 'spain' के बीच 50:50 बंटे हैं। कई मामलों में, आपके पास बस यही होता है और आप केवल शब्दों की परिमाणात्मक आवृत्ति माप सकते हैं और कुछ संबंधों का अनुमान लगा सकते हैं। इस मामले में, आपके पास प्रत्येक दस्तावेज़ के बारे में कुछ डेटा भी है।

यहाँ वेटेड आवृत्ति स्पष्ट रूप से अलग है, और बंटवारा 80:20 है। यानी, भले ही 'spain' और 'france' आपके ट्वीट्स में एक-एक बार आए हों, आपके पाठकों के दृष्टिकोण से पहला 800 बार जबकि दूसरा 200 बार प्रकट हुआ। यह बड़ा फर्क है!

defaultdict का उपयोग करके सरल शब्द-आवृत्ति

अब इसी तरह के दस्तावेज़-समूह के लिए थोड़ा अधिक विस्तार वाला उदाहरण देखें:

दस्तावेज़व्यूज़
france200
spain180
spain beaches170
france beaches160
spain best beaches160

अब आप दस्तावेज़ों पर लूप लगाते हैं, उन्हें शब्दों में विभाजित करते हैं, और प्रत्येक शब्द की आवृत्ति गिनते हैं:

 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

ऊपर के लूप में, पहली पंक्ति text_list पर एक-एक करके लूप लगाती है। दूसरी पंक्ति (हर दस्तावेज़ के भीतर) प्रत्येक आइटम के शब्दों पर लूप लगाती है, जिन्हें स्पेस कैरेक्टर से विभाजित किया गया है (जो किसी और कैरेक्टर ('-', ',', '_', आदि) से भी हो सकता था)।

जब आप word_freq[word] को कोई मान असाइन करने की कोशिश करते हैं, तो दो संभावनाएँ होती हैं:

  1. कुंजी word मौजूद है: ऐसे में असाइनमेंट हो जाता है (एक जोड़ते हुए)
  2. कुंजी word word_freq में नहीं है, इस स्थिति में defaultdict वह डिफ़ॉल्ट फ़ंक्शन बुलाता है जो परिभाषा के समय दिया गया था, जो यहाँ int है।

int कॉल होने पर शून्य लौटाता है। अब कुंजी मौजूद है, उसका मान शून्य है, और वह अपने मान में 1 जोड़ने के लिए तैयार है।

हालाँकि पहले तालिका में शीर्ष शब्द 'france' था, लेकिन प्रत्येक दस्तावेज़ के भीतर सभी शब्दों की गिनती करने के बाद हम देखते हैं कि 'spain' और 'beaches' पहले स्थान पर बराबरी पर हैं। यह छिपे रुझानों का पता लगाने में महत्वपूर्ण है, खासकर जब जिन दस्तावेज़ों से आप निपट रहे हैं उनकी संख्या दसियों, सैकड़ों या हजारों में हो।

वेटेड शब्द-आवृत्ति

अब जब आप दस्तावेज़-समूह में प्रत्येक शब्द की आवृत्ति गिन चुके हैं, तो आप वेटेड आवृत्ति देखना चाहते हैं। यानी, आप देखना चाहते हैं कि आपके पाठकों को वे शब्द कितनी बार दिखाई दिए, इसकी तुलना में कि आपने उन्हें कितनी बार इस्तेमाल किया।

पहली तालिका में, शब्दों की परिमाणात्मक आवृत्ति 'spain' और 'france' के बीच बराबर थी, लेकिन 'spain' का वजन स्पष्ट रूप से बहुत अधिक था, क्योंकि उसका मान 800 था, जबकि 'france' का 200।

लेकिन दूसरी, थोड़ी अधिक जटिल, तालिका के लिए वेटेड शब्द-आवृत्ति क्या होगी?

आइए पता लगाएँ!

आप ऊपर उपयोग किए गए कुछ कोड का पुन: उपयोग कर सकते हैं, लेकिन कुछ जोड़ के साथ:

 # 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

कुछ टिप्पणियाँ:

  • हालाँकि कुल मिलाकर 'france' सबसे ऊँची वाक्यांश थी, वेटेड आवृत्ति लेने पर 'spain' और 'beaches' अधिक प्रमुख दिखते हैं।
  • rel_value एक साधारण भागफल है, जो प्रत्येक शब्द की प्रति उपस्थिति मान देता है।
  • rel_value को देखते हुए आप यह भी देखते हैं कि भले ही 'france' wtd_freq मीट्रिक पर काफी नीचे है, फिर भी इसमें संभावनाएँ दिखती हैं, क्योंकि प्रति उपस्थिति मान अधिक है। यह उदाहरण के लिए 'france' पर आपकी कंटेंट कवरेज बढ़ाने का संकेत दे सकता है।

आप ऐसे अन्य मीट्रिक्स भी जोड़ना चाहेंगे जो प्रत्येक प्रकार की आवृत्ति का प्रतिशत और संचयी प्रतिशत दिखाएँ, ताकि आपको बेहतर परिप्रेक्ष्य मिल सके कि कुल का bulk कितने शब्द बनाते हैं, यदि कोई हो:

 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

और भी बहुत कुछ विश्लेषित किया जा सकता है, और अधिक डेटा के साथ आपको आमतौर पर और ज्यादा चौंकाने वाली बातें मिलेंगी।

तो वास्तविक दुनिया में, वास्तविक डेटा के साथ यह कैसा दिख सकता है?

आप फ़िल्मों के शीर्षक देखेंगे, किन शब्दों का शीर्षकों में सबसे अधिक उपयोग हुआ है — जो परिमाणात्मक आवृत्ति है — और कौन से शब्द सबसे अधिक राजस्व से जुड़े हैं, यानी वेटेड आवृत्ति।

Boxoffice Mojo पर 15,000 से अधिक फ़िल्मों की सूची है, उनके संबंधित ग्रॉस रेवेन्यू और रैंक के साथ। requests और BeautifulSoup का उपयोग कर डेटा स्क्रैप करना शुरू करें — यदि आप चाहें तो यहाँ Boxoffice Mojo को अभी एक्सप्लोर कर सकते हैं:

 
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

आप देखेंगे कि कुछ संख्यात्मक मानों में विशेष वर्ण हैं ($, , और ^), और कुछ मान वास्तव में N/A हैं। इसलिए आपको उन्हें बदलना होगा:

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

अब आप सूची को pandas के DataFrame में बदलते हैं, कॉलम के उचित नाम देकर, और मनचाहे डेटा प्रकारों में कन्वर्ट करके।

 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' शब्द शीर्ष में से एक है, क्योंकि यह शीर्ष पंद्रह फ़िल्मों में से पाँच में आता है, और आप यह भी जानते हैं कि Star Wars श्रृंखला में और भी फ़िल्में हैं, जिनमें से कई शीर्ष पर हैं।

अब आपने जो कोड विकसित किया है उसका उपयोग करें और देखें कि यह इस डेटा सेट पर कैसे काम करता है। नीचे दिए गए कोड में नया कुछ नहीं है, आप बस सब कुछ एक फ़ंक्शन में रख रहे हैं:

 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

आश्चर्य नहीं कि 'स्टॉप वर्ड्स' सबसे ऊपर हैं, जो अधिकांश दस्तावेज़-संग्रहों के लिए लगभग समान होता है। आपके पास ये डुप्लीकेट में भी हैं, जहाँ कुछ कैपिटलाइज़्ड हैं और कुछ नहीं। इसलिए आपके पास दो स्पष्ट काम हैं:

  1. सभी स्टॉप वर्ड्स हटाएँ: यह आप फ़ंक्शन में एक नया पैरामीटर जोड़कर और अपनी स्टॉप-वर्ड्स सूची देकर कर सकते हैं।
  2. डुप्लीकेट हटाने के लिए सभी शब्दों को लोअर केस में हैंडल करें

यहाँ फ़ंक्शन का एक सरल अपडेट है (नया rm_words पैरामीटर, साथ ही पंक्तियाँ 6, 7 और 8):

# 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

 शब्दabs_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.000758640.023939326113297140.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

आइए उसी DataFrame को देखें जिसे abs_freq के आधार पर सॉर्ट किया गया है:

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

 शब्दabs_freqabs_percabs_perc_cumwtd_freqwtd_freq_percwtd_freq_perc_cumrel_value
26love2110.005928630.06954216042068850.002444380.1113997.60288e+06
2man1950.005479070.011182939670378540.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

अब दोनों की तुलना के लिए विज़ुअलाइज़ करें और छिपे हुए रुझान देखें:

 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()

बॉक्स ऑफिस डेटा से सबसे अधिक जुड़े शब्द

ऐसा लगता है कि कम से कम निर्माताओं और लेखकों के दिमाग में तो प्यार सब पर भारी पड़ता है! यह सभी फिल्म शीर्षकों में सबसे अधिक इस्तेमाल किया गया शब्द है। हालांकि, भारित आवृत्ति (बॉक्स-ऑफिस राजस्व) के मामले में यह उतना ऊपर नहीं है।

दूसरे शब्दों में, यदि आप सभी फिल्म शीर्षकों को देखें, तो 'love' वह शब्द होगा जो आपको सबसे अधिक मिलेगा। लेकिन दर्शकों की नजर में कौन-सा शब्द सबसे ज्यादा आया—इसे कुल कमाई को मीट्रिक मानकर आँका जाए—तो '2', 'star' और 'man' सबसे अधिक देखे गए होंगे, या सबसे अधिक राजस्व से जुड़े होंगे।

साफ़ करने के लिए: ये बहुत साधारण गणनाएँ हैं। जब आप कहते हैं कि 'love' शब्द की भारित आवृत्ति 1,604,106,767 है, तो इसका सरल मतलब यह है कि जिन सभी फिल्मों के शीर्षक में 'love' शामिल था, उनकी आजीवन कमाई का योग इतना था।

यह भी दिलचस्प है कि '2' शीर्ष पर है। जाहिर है यह शब्द नहीं है, लेकिन यह संकेत देता है कि फिल्म श्रृंखलाओं के दूसरे भाग बहुत बड़ी रकम जोड़ते हैं। '3' भी वैसा ही है, जो पाँचवें स्थान पर है। ध्यान दें कि 'part' और 'ii' भी शीर्ष दस में हैं, जो इसी बात की पुष्टि करते हैं।

'American' और 'movie' का सापेक्ष मान अधिक है।

इस फ़ंक्शन में प्रयुक्त स्टॉप वर्ड्स पर एक त्वरित टिप्पणी

आम तौर पर, आप यहाँ दी गई सूची से अधिक व्यापक स्टॉप वर्ड्स की सूची देंगे, खासकर यदि आप लेखों या सोशल मीडिया पोस्ट से निपट रहे हैं। उदाहरण के लिए nltk पैकेज कई भाषाओं में स्टॉप वर्ड्स की सूचियाँ देता है, जिन्हें डाउनलोड कर इस्तेमाल किया जा सकता है।

यहाँ के शब्द कुछ शीर्ष फिल्मों पर कुछ जाँचों के बाद चुने गए थे। इन में से कई आमतौर पर स्टॉप वर्ड्स माने जाते हैं, लेकिन फिल्म शीर्षकों के मामले में, उनमें से कुछ को रखना समझदारी लगी क्योंकि वे कुछ संकेत दे सकते हैं। उदाहरण के लिए, 'I', 'me', 'you' जैसे शब्द कुछ सामाजिक गतिशीलता की ओर इशारा कर सकते हैं। एक और कारण यह है कि फिल्म शीर्षक बहुत छोटे वाक्यांश होते हैं, और हम उनसे अधिक से अधिक अर्थ निकालने की कोशिश कर रहे हैं।

आप निश्चित रूप से अपने शब्दों के सेट के साथ इसे आज़मा सकते हैं, और थोड़े अलग परिणाम देख सकते हैं।

मूल फिल्मों की सूची पर नज़र डालें, तो दिखता है कि कुछ शीर्ष शब्द शीर्ष दस में भी नहीं आते, और यही वह तरह की अंतर्दृष्टि है जिसे हम इस तरीके से उजागर करने की कोशिश कर रहे हैं।

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

अगला, मेरा मानना है कि जिन शीर्ष शब्दों में दिलचस्पी है, उन्हें और गहराई से देखना समझदारी होगी। आइए उन फिल्मों को फ़िल्टर करें जिनमें '2' हो और देखें:

(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

आइए शीर्ष 'star' फिल्मों पर भी एक नज़र डालें:

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

और, अंत में, शीर्ष 'man' फिल्में:

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

अगले चरण और सुधार

पहले कदम के रूप में, आप और अधिक शब्द जुटाने की कोशिश कर सकते हैं: फ़िल्मी शीर्षक अत्यंत छोटे होते हैं और कई बार शब्दों के शाब्दिक अर्थ नहीं बताते। उदाहरण के लिए, godfather वास्तव में वह व्यक्ति होता है जो किसी बच्चे के बपतिस्मा का साक्षी बनता है और उसकी देखभाल का वचन देता है (या फिर कोई माफ़िया जो शौक के लिए हत्या करता है?!).

एक और अभ्यास के रूप में, फ़िल्म शीर्षक के अलावा अधिक विस्तृत वर्णन जुटाने की कोशिश करें। उदाहरण के लिए:

"एक कंप्यूटर हैकर को रहस्यमयी बाग़ियों से अपनी वास्तविकता की असली प्रकृति और नियंत्रकों के खिलाफ़ युद्ध में अपनी भूमिका के बारे में पता चलता है।"

यह हमें 'The Matrix' की तुलना में फ़िल्म के बारे में कहीं अधिक बताता है।

वैकल्पिक रूप से, आप अपना विश्लेषण समृद्ध करने के लिए नीचे दिए गए रास्तों में से किसी एक को भी अपना सकते हैं:

  • बेहतर सांख्यिकीय विश्लेषण: चरम मानों/आउटलायर्स को संभालना, अन्य मीट्रिक का उपयोग करना।
  • पाठ खनन: मिलते-जुलते शब्दों और विषयों को साथ समूहित करना ('happy', 'happiness', 'happily', आदि)
  • सूक्ष्म विश्लेषण: अलग-अलग वर्षों/दशकों या कुछ विशेष प्रोडक्शन स्टूडियो के लिए वही फ़ंक्शन चलाना।

आप स्वयं इस डेटा के साथ-साथ अन्य डेटा का भी अन्वेषण करना चाहेंगे:

ठीक है, अब आपने फ़िल्म शीर्षकों में शब्दों की गणनाओं का अन्वेषण कर लिया है, और निरपेक्ष तथा वेटेड आवृत्तियों के बीच का अंतर देखा है, और यह भी कि इनमें से किसी एक को छोड़ देने से तस्वीर का बड़ा हिस्सा छूट सकता है। आपने इस पद्धति की सीमाएँ भी देखी हैं, और अपने विश्लेषण को बेहतर करने के कुछ सुझाव भी पाए हैं।

आपने एक विशेष फ़ंक्शन बनाने की प्रक्रिया पूरी कर ली है, जिसे आप आसानी से किसी भी ऐसे समान पाठ्य डेटा सेट (जिसमें संख्याएँ हों) पर चला सकते हैं, और समझ लिया है कि यह ऐसे डेटा सेट की आपकी समझ को कैसे बेहतर कर सकता है।

इसे आज़माएँ—अपने ट्वीट्स के प्रदर्शन, अपनी वेबसाइट के URLs, अपने Facebook पोस्ट्स, या किसी भी अन्य समान डेटा सेट का विश्लेषण करके देखें।

शायद आपके लिए कोड सहित रिपॉज़िटरी क्लोन करना और खुद प्रयास करना आसान होगा।

word_frequency फ़ंक्शन advertools पैकेज का हिस्सा है, जिसे आप डाउनलोड कर अपने कार्य/अनुसंधान में उपयोग करके देख सकते हैं।

देखें और बताइए! @eliasdabbas

DataCamp के Python Dictionaries Tutorial पर नज़र डालें ताकि आप शब्द आवृत्ति बनाना सीख सकें, और Web Scraping & NLP in Python ट्यूटोरियल देखें ताकि आप शब्द आवृत्ति वितरण को प्लॉट करना सीख सकें।

विषय