【问题标题】:Iterate nltk.tokenize across all rows of a pandas dataframe在 pandas 数据帧的所有行中迭代 nltk.tokenize
【发布时间】:2019-09-30 21:30:29
【问题描述】:

感谢您为这个看似愚蠢的问题提供的帮助。我已经将一个 sqlite 表拉入了一个 pandas 数据框中,这样我就可以标记并计算一系列推文中单词的频率。

使用下面的代码,我可以为第一条推文生成这个。如何迭代整个表?

conn = sqlite3.connect("tweets.sqlite")
data = pd.read_sql_query("select tweet_text from tweets_new;", conn)

tokenizer=RegexpTokenizer(r'\w+')
tokens=tokenizer.tokenize(data['tweet_text'][0])

words = nltk.FreqDist(tokens)

unigram_df = pd.DataFrame(words.most_common(),
                             columns=["WORD","COUNT"])

unigram_df

当我将值更改为单行以外的任何值时,我收到以下错误:

TypeError: expected string or buffer

我知道还有其他方法可以做到这一点,但我需要按照这些思路来做,因为我打算接下来如何使用输出。感谢您提供的任何帮助!

我试过了:

%%time

tokenizer = RegexpTokenizer(r'\w+')  

print "Cleaning the tweets...\n"
for i in xrange(0,len(df)):
    if( (i+1)%1000000 == 0 ):  
        tokens=tokenizer.tokenize(df['tweet_text'][i])
        words = nltk.FreqDist(tokens)

这看起来应该可以,但仍然只返回第一行中的单词。

【问题讨论】:

  • 当您说“将值更改为单行以外的任何值”时,请发布您使用的代码。
  • 谢谢,用我试过的方法编辑。

标签: python pandas nltk tokenize


【解决方案1】:

我认为使用CountVectorizer 可以更简洁地解决您的问题。我给你举个例子。给定以下输入:

from sklearn.feature_extraction.text import CountVectorizer
import pandas as pd 

corpus_tweets = [['I love pizza and hambuerger'],['I love apple and chips'], ['The pen is on the table!!']]
df = pd.DataFrame(corpus_tweets, columns=['tweet_text'])

您可以使用以下几行来创建您的词袋模板:

count_vect = CountVectorizer()
X_train_counts = count_vect.fit_transform(df.tweet_text)

可以打印得到的词汇:

count_vect.vocabulary_
# ouutput: {'love': 5, 'pizza': 8, 'and': 0, 'hambuerger': 3, 'apple': 1, 'chips': 2, 'the': 10, 'pen': 7, 'is': 4, 'on': 6, 'table': 9}

并获取带有字数的数据框:

df_count = pd.DataFrame(X_train_counts.todense(), columns=count_vect.get_feature_names())

   and  apple  chips  hambuerger  is  love  on  pen  pizza  table  the
0    1      0      0           1   0     1   0    0      1      0    0
1    1      1      1           0   0     1   0    0      0      0    0
2    0      0      0           0   1     0   1    1      0      1    2

如果对你有用,可以将counts的dataframe与语料库的dataframe合并:

pd.concat([df, df_count],  axis=1)

                    tweet_text  and  apple  chips  hambuerger  is  love  on  \
0  I love pizza and hambuerger    1      0      0           1   0     1   0   
1       I love apple and chips    1      1      1           0   0     1   0   
2    The pen is on the table!!    0      0      0           0   1     0   1   

   pen  pizza  table  the  
0    0      1      0    0  
1    0      0      0    0  
2    1      0      1    2  

如果您想获取包含每个文档的 <word, count> 对的字典,此时您需要做的就是:

dict_count = df_count.T.to_dict()

{0: {'and': 1,
  'apple': 0,
  'chips': 0,
  'hambuerger': 1,
  'is': 0,
  'love': 1,
  'on': 0,
  'pen': 0,
  'pizza': 1,
  'table': 0,
  'the': 0},
 1: {'and': 1,
  'apple': 1,
  'chips': 1,
  'hambuerger': 0,
  'is': 0,
  'love': 1,
  'on': 0,
  'pen': 0,
  'pizza': 0,
  'table': 0,
  'the': 0},
 2: {'and': 0,
  'apple': 0,
  'chips': 0,
  'hambuerger': 0,
  'is': 1,
  'love': 0,
  'on': 1,
  'pen': 1,
  'pizza': 0,
  'table': 1,
  'the': 2}}

注意:将 稀疏 numpy 矩阵X_train_counts 转换为数据框不是一个好主意。但了解和可视化模型的各个步骤会很有用。

【讨论】:

  • 感谢您的建议。我不会对细节感到厌烦,但我一直在尝试这样做,因为它允许我制定一个唯一值和频率的列表,并使用 sqlite 语法将其插入到 sqlite db 中。你的方法听起来很明智,但也给我带来了其他痛点。
  • 如果我理解正确,您想要与此数据框对应的字典,并且您希望具有以下结构:{id_doc1: {word1: count1, ... wordN: countN}}, id_doc2: {word1: count1, ... wordN: countN} ,....} 对吗?您可以通过以下方式快速获得:df_count.T.to_dict ()
  • 非常感谢@Massifox 实际上,您在第 2 步和第 3 步生成的内容最接近我需要的内容 - 所有行的唯一值列,以及每个单词出现频率的列。为什么将其转换为数据框是个坏主意?
  • @SiJo 出于效率考虑。此操作效率不高有两个原因:1)生成的矩阵是稀疏的(许多值为 0),因此它不必要地占用内存,实际上 CountVectorizer 会返回一个“压缩”矩阵来有效地表示这个矩阵类型。创建一个数据框会扩展这个矩阵,失去优化并且无用地占用比必要更多的内存,而熊猫并不是特别有效(以这种方式使用)来管理这类问题。 2) 由于矩阵的大小,计算变得更加昂贵。
  • 感谢您的帮助@Massifox。我认为鉴于您的 cmets,我将无法扩展您建议的方法。
【解决方案2】:

在所有行上创建DataFrame 循环后:

tokenizer = RegexpTokenizer(r'\w+')
fdist = FreqDist()
for txt in data['tweet_text']:
      for word in tokenizer.tokenize(txt):
          fdist[word.lower()] += 1

【讨论】:

  • 谢谢。我试过这个,但似乎没有用。当我尝试调用数据框时,出现以下错误:AttributeError: 'unicode' object has no attribute 'most_common'
  • 频率一词在fdist 中(试试fdist.tabulate())。在我的回答中没有使用 Pandas。
  • 谢谢@luis.parravicini - 我可以用 fdist.tabulate() 来制表。但我试图从所有行中生成一列唯一值,以及每个单词出现频率的列。知道如何重新计算输出以实现这一目标吗?
【解决方案3】:

如果有人对这个小众用例感兴趣,下面是我最终能够完成的代码:

conn = sqlite3.connect("tweets.sqlite")
data = pd.read_sql_query("select tweet_text from tweets_new;", conn)

alldata = str(data)

tokenizer=RegexpTokenizer(r'\w+')
tokens=tokenizer.tokenize(alldata)

words = nltk.FreqDist(tokens)

unigram_df = pd.DataFrame(words.most_common(),
                             columns=["WORD","COUNT"])

感谢大家的帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-11
    • 1970-01-01
    • 2017-06-18
    • 2022-09-29
    • 2022-01-18
    • 2014-10-31
    • 2020-06-24
    • 1970-01-01
    相关资源
    最近更新 更多