pandas 在Python中有效地总结大数据上的n-gram

chhkpiq4  于 2023-10-14  发布在  Python
关注(0)|答案(1)|浏览(82)

希望你过得好!我有一个非常大的数据集,大约有600万条记录,它看起来像这个片段:

data = pd.DataFrame({
    'ID': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'],
    'TEXT': [
        "Mouthwatering BBQ ribs cheese, and coleslaw.",
        "Delicious pizza with pepperoni and extra cheese.",
        "Spicy Thai curry with cheese and jasmine rice.",
        "Tiramisu dessert topped with cocoa powder.",
        "Sushi rolls with fresh fish and soy sauce.",
        "Freshly baked chocolate chip cookies.",
        "Homemade lasagna with layers of cheese and pasta.",
        "Gourmet burgers with all the toppings and extra cheese.",
        "Crispy fried chicken with mashed potatoes and extra cheese.",
        "Creamy tomato soup with a grilled cheese sandwich."
    ],
    'DATE': [
        '2023-02-01', '2023-02-01', '2023-02-01', '2023-02-01', '2023-02-02',
        '2023-02-02', '2023-02-01', '2023-02-01', '2023-02-02', '2023-02-02'
    ]
})

我想从列'TEXT'中生成bigram和trigram。我对trigram和bigram的两种类型的ngrams感兴趣:一旦我们有了这些,我想通过唯一的"日期"来总结(计算唯一的ID频率)这些ngram。这意味着如果一个ngram在一个ID中出现多次,我将只计算一次,因为我想知道它最终出现在多少个不同的"ID"中。
我对Python还是个新手。我来自R世界,其中有一个名为quanteda的库,它使用C编程和并行计算。搜索这些ngrams看起来像这样:

corpus_food %>%
  tokens(remove_punct = TRUE) %>% 
  tokens_ngrams(n = 2) %>% 
  tokens_select(pattern = "^extra", valuetype = "regex") %>%
  dfm() %>%
  dfm_group(groups = lubridate::date(DATE)) %>%
  textstat_frequency()

得到我想要的结果:

feature frequency rank docfreq group
1 extra_cheese         3    1       2   all

我想要的结果看起来像这样:
| Ngram|非唯一的|组|
| - -|- -|- -|
| 奶酪和|3| 2023年2月1日|
| 和额外|2| 2023年2月1日|
| 额外的奶酪|2| 2023年2月1日|
| 多加奶酪|2| 2023年2月1日|
| 令人垂涎的烧烤|1| 2023年2月1日|
| 烧烤排骨|1| 2023年2月1日|
| 排骨乳酪|1| 2023年2月1日|
| 和凉拌卷心菜|1| 2023年2月1日|
| 令人垂涎的烧烤排骨|1| 2023年2月1日|
| 烧烤芝士排骨|1| 2023年2月1日|
| 排骨奶酪和|1| 2023年2月1日|
| 奶酪和凉拌卷心菜|1| 2023年2月1日|
| 美味的比萨|1| 2023年2月1日|
| 披萨|1| 2023年2月1日|
| 意大利辣香肠|1| 2023年2月1日|
| 辣香肠和|1| 2023年2月1日|
| 美味的比萨饼|1| 2023年2月1日|
| 意大利辣香肠比萨饼|1| 2023年2月1日|
| 意大利辣香肠,|1| 2023年2月1日|
| 意大利辣香肠和额外的|1| 2023年2月1日|
| 香辣泰式|1| 2023年2月1日|
| 泰国咖喱|1| 2023年2月1日|
我不是在比较两种语言,Python和R。它们是惊人的,但目前,我感兴趣的是一个非常直接和快速的方法来实现我的结果在Python中。如果你不使用gensim库,但知道如何在python中以更快更有效的方式实现我所寻找的内容,我将是开放的,我是一个超级细心和活跃的用户,肯定会渴望并支持找到解决方案。请善待我,因为我是Python的新手,我的心理健康此刻正处于崩溃的边缘。
到目前为止,我已经找到了一种方法来创建bigram和trigram,但我不知道如何执行那些以"extra"开头的选择,以及那些不这样做的人,创建ngrams的过程需要一个多小时,所以我会采取所有关于如何减少时间的建议,谢谢
解决方法:

import nltk
from nltk import bigrams
from nltk.util import trigrams 
from nltk.tokenize import word_tokenize

data['bigrams'] = data['TEXT'].apply(lambda x: list(bigrams(word_tokenize(x))))
data['trigrams'] = data['TEXT'].apply(lambda x: list(trigrams(word_tokenize(x))))

阅读通过一些帖子,有些人建议使用gensim库,你们怎么看?

vd2z7a6w

vd2z7a6w1#

使用sklearn的CountVectorizer使用ngram_range参数很容易找到ngram。
你可以创建一个document-term matrix,只使用大小为2和3的ngram,然后附加到你的原始数据集,并使用pandas进行旋转和聚合来找到你需要的东西。
首先,我们将获取文档-术语矩阵并附加到原始数据:

# Perform the count vectorization, keeping bigrams and trigrams only
from sklearn.feature_extraction.text import CountVectorizer
cv = CountVectorizer(ngram_range=(2,3))
X = cv.fit_transform(data['TEXT'])

# Create dataframe of document-term matrix
cv_df = pd.DataFrame(X.todense(), columns=cv.get_feature_names_out())

# Append to original data
df = pd.concat([data, cv_df], axis=1)

然后我们按ID和日期分组,并在计数大于0的地方进行过滤,以找到每个2或3-gram出现的ID-日期组合,然后计算每个的唯一ID:

# Group and pivot
pivoted_df = df.groupby(['ID','DATE']).sum().stack().reset_index()
pivoted_df.columns = ['ID', 'DATE', 'ngram', 'count']

# Find n-grams which appear for each ID-DATE combo and count unique ids
pivoted_df = pivoted_df[pivoted_df['count']>0]
pivoted_df.groupby(['DATE','ngram']).nunique('ID').reset_index()

最后,我们可以为ngram大小创建额外的列,以及ngram是否以extra开头,并用于过滤:

# Add additional columns for ngram size 
pivoted_df['ngram_size'] = pivoted_df['ngram'].str.split().str.len()

# Add additional column for starting with extra
pivoted_df['extra'] = pivoted_df['ngram'].str.startswith('extra')

# Find all the 2-grams that start with "extra"
pivoted_df[(pivoted_df['extra']) & (pivoted_df['ngram_size']==2)]

也就是说,如果你有600万条记录,你就有了一个很大的数据集,使用这种方法你肯定会遇到内存问题。您可能希望将数据筛选到您最感兴趣的部分,并确保在CountVectorizer中使用min_df参数,以保持数据易于处理。

相关问题