从 pandas DataFrame 创建词密度矩阵的高效方法
我正在尝试从一个pandas数据框中创建一个术语密度矩阵,这样我就可以对数据框中出现的术语进行评分。我还希望能够保留数据的“空间”特性(在帖子末尾的评论中有我想表达的例子)。
我对pandas和NLTK还不太熟悉,所以我希望我的问题能用一些现有的工具解决。
我的数据框中有两列比较重要:比如说“标题”和“页面”。
import pandas as pd
import re
df = pd.DataFrame({'title':['Delicious boiled egg','Fried egg ','Split orange','Something else'], 'page':[1, 2, 3, 4]})
df.head()
page title
0 1 Delicious boiled egg
1 2 Fried egg
2 3 Split orange
3 4 Something else
我的目标是清理文本,并将感兴趣的术语传递到一个TDM数据框中。我使用了两个函数来帮助我清理字符串。
import nltk.classify
from nltk.tokenize import wordpunct_tokenize
from nltk.corpus import stopwords
import string
def remove_punct(strin):
'''
returns a string with the punctuation marks removed, and all lower case letters
input: strin, an ascii string. convert using strin.encode('ascii','ignore') if it is unicode
'''
return strin.translate(string.maketrans("",""), string.punctuation).lower()
sw = stopwords.words('english')
def tok_cln(strin):
'''
tokenizes string and removes stopwords
'''
return set(nltk.wordpunct_tokenize(strin)).difference(sw)
还有一个函数用来处理数据框的操作。
def df2tdm(df,titleColumn,placementColumn,newPlacementColumn):
'''
takes in a DataFrame with at least two columns, and returns a dataframe with the term density matrix
of the words appearing in the titleColumn
Inputs: df, a DataFrame containing titleColumn, placementColumn among others
Outputs: tdm_df, a DataFrame containing newPlacementColumn and columns with all the terms in df[titleColumn]
'''
tdm_df = pd.DataFrame(index=df.index, columns=[newPlacementColumn])
tdm_df = tdm_df.fillna(0)
for idx in df.index:
for word in tok_cln( remove_punct(df[titleColumn][idx].encode('ascii','ignore')) ):
if word not in tdm_df.columns:
newcol = pd.DataFrame(index = df.index, columns = [word])
tdm_df = tdm_df.join(newcol)
tdm_df[newPlacementColumn][idx] = df[placementColumn][idx]
tdm_df[word][idx] = 1
return tdm_df.fillna(0,inplace = False)
tdm_df = df2tdm(df,'title','page','pub_page')
tdm_df.head()
这个过程的结果是:
pub_page boiled egg delicious fried orange split something else
0 1 1 1 1 0 0 0 0 0
1 2 0 1 0 1 0 0 0 0
2 3 0 0 0 0 1 1 0 0
3 4 0 0 0 0 0 0 1 1
但是在处理大数据集时(输出有十万行,几千列)速度非常慢。我的两个问题是:
我能加快这个实现的速度吗?
有没有其他工具可以用来完成这个任务?
我希望能够保留数据的“空间”特性,比如如果“蛋”这个词在第1到第10页出现得很频繁,然后在第500到第520页又频繁出现,我想知道这一点。
2 个回答
0
herrfz 提供了一种处理这个问题的方法,但我想指出的是,使用 Python 的集合来创建一个词频数据结构其实是没什么用的,因为集合只保存唯一的对象。这样你就无法记录每个词的出现次数,只能知道某一行中是否有这个词。
return set(nltk.wordpunct_tokenize(strin)).difference(sw)
为了去掉一些常用的无意义词,你可以做类似这样的操作:
tokens_stripped = [token for token in tokens
if token not in stopwords]
在进行分词之后。
20
你可以使用 scikit-learn 里的 CountVectorizer:
In [14]: from sklearn.feature_extraction.text import CountVectorizer
In [15]: countvec = CountVectorizer()
In [16]: countvec.fit_transform(df.title)
Out[16]:
<4x8 sparse matrix of type '<type 'numpy.int64'>'
with 9 stored elements in Compressed Sparse Column format>
它会返回一个稀疏的词项文档矩阵,因为这种矩阵通常很大,而且大部分地方都是空的。
对于你的具体例子,我想把它转换回 DataFrame 还是可以的:
In [17]: pd.DataFrame(countvec.fit_transform(df.title).toarray(), columns=countvec.get_feature_names())
Out[17]:
boiled delicious egg else fried orange something split
0 1 1 1 0 0 0 0 0
1 0 0 1 0 1 0 0 0
2 0 0 0 0 0 1 0 1
3 0 0 0 1 0 0 1 0
[4 rows x 8 columns]