基于

时间:2016-12-16 16:19:43

标签: python string pandas grouping

我正在尝试创建单词组。首先,我在计算所有的话。然后我按字数计算前10个单词。然后我想根据前10个单词创建10组单词。每个单词组由顶部单词之前和之后的所有单词组成。

我的调查结果存储在python pandas数据框中,结构如下

Question_ID | Customer_ID | Answer
  1           234         Data is very important to use because ... 
  2           234         We value data since we need it ... 

我还将答案列保存为字符串。

我使用以下代码在单词之前和之后找到3个单词(我实际上必须在答案列中创建一个字符串)

answers_str = df.Answer.apply(str)
for value in answers_str:
   non_data = re.split('data|Data', value)
   terms_list = [term for term in non_data if len(term) > 0] # skip empty terms
   substrs = [term.split()[0:3] for term in terms_list]  # slice and grab first three terms
   result = [' '.join(term) for term in substrs] # combine the terms back into substrings
   print result

我一直在手动创建单词组 - 但有没有办法在python中进行?

因此,基于上面显示的示例,具有字数的组将如下所示:

group "data": 
              data : 2
              important: 1
              value: 1
              need:1

然后当它遍历整个文件时,会有另一个组:

group "analytics:
              analyze: 5
              report: 7
              list: 10
              visualize: 16

想法是摆脱“我们”,“到”,“是” - 但我可以手动完成,如果那是不可能的话。

然后建立10个最常用的单词(通过单词计数)然后创建10个组,其中单词位于前10个单词的前面和后面。

1 个答案:

答案 0 :(得分:2)

我们可以使用正则表达式。我们将使用这个正则表达式

((?:\b\w+?\b\s*){0,3})[dD]ata((?:\s*\b\w+?\b){0,3})

你可以自己测试here,在每次出现数据之前和之后提取三个单词

首先,让我们从字符串中删除所有不喜欢的单词。

import re

#    If you're processing a lot of sentences, it's probably wise to preprocess
#the pattern, assuming that bad_words is the same for all sentences
def remove_words(sentence, bad_words):
    pat = r'(?:{})'.format(r'|'.join(bad_words))
    return re.sub(pat, '', sentence, flags=re.IGNORECASE)

我们希望得到每行中包含数据的单词

data_pat = r'((?:\b\w+?\b\s*){0,3})[dD]ata((?:\s*\b\w+?\b){0,3})'
res = re.findall(pat, s, flags=re.IGNORECASE)

给我们一个字符串元组列表。我们希望在分割后获得这些字符串的列表。

from itertools import chain
list_of_words = list(chain.from_iterable(map(str.split, chain.from_iterable(map(chain, chain(res))))))

这不漂亮,但它确实有效。基本上,我们将元组从列表中拉出来,从每个元组中拉出字符串,然后拆分每个字符串,然后将所有字符串从它们最终列出的列表中拉出来。

让我们将这一切与您的pandas代码放在一起。 pandas不是我最强的区域,所以如果你看到奇怪的样子,请不要认为我没有犯过一些基本的错误。

import re
from itertools import chain
from collections import Counter    

def remove_words(sentence, bad_words):
    pat = r'(?:{})'.format(r'|'.join(bad_words))
    return re.sub(pat, '', sentence, flags=re.IGNORECASE)

bad_words = ['we', 'is', 'to']
sentence_list = df.Answer.apply(lambda x: remove_words(str(x), bad_words))
c = Counter()
data_pat = r'((?:\b\w+?\b\s*){0,3})data((?:\s*\b\w+?\b){0,3})'
for sentence in sentence_list:
    res = re.findall(data_pat, sentence, flags=re.IGNORECASE)
    words = chain.from_iterable(map(str.split, chain.from_iterable(map(chain, chain(res)))))
    c.update(words)

我们正在使用的正则表达式的好处是所有复杂的部分都不关心我们使用的是什么词。稍作修改,我们就可以制作格式字符串

base_pat = r'((?:\b\w+?\b\s*){{0,3}}){}((?:\s*\b\w+?\b){{0,3}})'

这样

base_pat.format('data') == data_pat

因此,对于某些单词列表,我们希望收集有关key_words

的信息
import re
from itertools import chain
from collections import Counter    

def remove_words(sentence, bad_words):
    pat = r'(?:{})'.format(r'|'.join(bad_words))
    return re.sub(pat, '', sentence, flags=re.IGNORECASE)


bad_words = ['we', 'is', 'to']

sentence_list = df.Answer.apply(lambda x: remove_words(str(x), bad_words))

key_words = ['data', 'analytics']
d = {}

base_pat = r'((?:\b\w+?\b\s*){{0,3}}){}((?:\s*\b\w+?\b){{0,3}})'
for keyword in key_words:
    key_pat = base_pat.format(keyword)
    c = Counter()
    for sentence in sentence_list:
        res = re.findall(key_pat, sentence, flags=re.IGNORECASE)
        words = chain.from_iterable(map(str.split, chain.from_iterable(map(chain, chain(res)))))
        c.update(words)
    d[keyword] = c

现在我们有一个字典d,用于将关键字(例如dataanalytics)映射到Counter,将不在我们黑名单中的字词映射到其中相关关键字的附近。像

这样的东西
d= {'data'      : Counter({ 'important' : 2,
                            'very'      : 3}),
    'analytics' : Counter({ 'boring'    : 5,
                            'sleep'     : 3})
   }

关于我们如何获得前10个单词,这基本上是Counter最擅长的。

key_words, _ = zip(*Counter(w for sentence in sentence_list for w in sentence.split()).most_common(10))