跳至主要内容

文本中词语的绝对频率与加权频率

在本教程中,您将了解文本挖掘中的词语绝对与加权频率,以及如何使用 defaultdict 和 pandas DataFrame 进行计算。
· 15分钟 阅读

使用 AI 探索

文本挖掘中的一组重要指标与某个语料库(文本文档集合)中词语(或任意标记)的出现频率相关。不过,当每篇文档都带有一个用于描述某个属性的数值时,您还可以使用另一组附加指标。

一些示例:

  • 推文及其对应的互动次数。
  • URL 及其页面浏览量与跳出量。
  • 电影片名及其总票房。
  • 关键词及其展示次数、点击量与转化量。

在本教程中,

  • 您将首先创建一个简单函数,用于计算并比较文档语料库中词语的绝对出现次数与加权出现次数。在某些情况下,这能揭示仅查看前十个左右数值时不易观察到的隐藏趋势与聚合。而且,它们往往与绝对词频不同。
  • 接着,您将查看一个真实数据集(电影片名与总票房),并尝试发现隐藏趋势。提前剧透:love 将以某种方式出现!
  • 您将使用 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 会返回 0。此时键已存在,其值为 0,接下来即可在其基础上再加 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”的内容覆盖。

您或许还想加入其他指标,展示各类频率的百分比与累计百分比,这样可以更好地了解是否有少数词语占据了总量的大头:

 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”是高频词之一,因为它出现在前十五部电影中的五部之中,而且我们也知道《星球大战》系列还有更多影片,其中几部也位居前列。

现在让我们利用您编写的代码,看看它在该数据集上的表现。下面的代码并无新内容,我们只是把它封装成了一个函数:

 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

 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

让我们基于 abs_freq 对同一 DataFrame 排序查看:

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

现在让我们进行可视化,对比两者并寻找隐藏趋势:

 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

至少在制片人和编剧的心中,爱似乎确实无往不胜!它是所有电影片名中最常用的词。不过在加权频率(票房)方面,它并不靠前。

换句话说,如果您查看所有电影的片名,“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”等)。
  • 更细粒度的分析:按不同年份/年代或特定制片厂分别运行相同的函数。

您也许会对自行探索数据以及其他数据感兴趣:

好的,如今您已经探索了电影片名中的词语计数,了解了绝对频率与加权频率之间的差异,以及忽略其中任何一个如何可能错失全貌的一大块内容。您也看到了这种方法的局限性,并获得了一些改进分析的建议。

您完成了创建一个专用函数的过程,可轻松用于分析任何带有数值的相似文本数据集,也理解了这能如何提升对这类数据集的认识。

不妨试试分析您的推文表现、网站 URL、Facebook 帖子,或您遇到的任何类似数据集。

直接克隆该仓库获取代码,亲自尝试或许更便捷。

word_frequency 函数已收录在 advertools 包中,您可以下载并在工作/研究中试用。

欢迎查看并告诉我您的想法!@eliasdabbas

查看 DataCamp 的Python 字典教程以学习如何创建词频,以及Python 中的网页抓取与 NLP教程以学习如何绘制词频分布。

主题