在Python 2.7中使用pandas我试图计算一个短语(例如,#34;非常好")出现在CSV文件中存储的文本中的次数。我有多个短语和多个文本。我使用以下代码成功完成了第一部分:
<key>NSLocationWhenInUseUsageDescription</key>
<string>The spirit of stack overflow is coders helping coders</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>I have learned more on stack overflow than anything else</string>
但是,如果短语前面有不同的短语(例如,&#34;它不是&#34;),我就不想计算短语。因此我使用了负面的后观断言:
for row in df_book.itertuples():
index, text = row
normed = re.sub(r'[^\sa-zA-Z0-9]', '', text).lower().strip()
for row in df_phrase.itertuples():
index, phrase = row
count = sum(1 for x in re.finditer(r"\b%s\b" % (re.escape(phrase)), normed))
file.write("%s," % (count))
这种方法的问题在于它记录了从df_negations数据帧中提取的每个否定值。因此,如果发现者没有找到&#34;它不是非常好&#39;&#34;,那么它将记录一个0.等等每一个可能的否定。
我真正想要的只是在没有前面的短语的情况下使用短语的总次数。换句话说,我希望每次都能算上非常好的&#34;发生,但只有当我的否定列表中没有否定之前(&#34;它不是&#34;)时才会发生。
另外,我非常高兴听到关于让流程更快地运行的建议。我有100多个短语,100多个否定和100多万个文本。
答案 0 :(得分:0)
我真的不做大熊猫,但是这个俗气的非熊猫版本会根据你发给我的数据给出一些结果。
主要的复杂性是Python re
模块不允许可变宽度负面的后置断言。因此,此示例查找匹配的短语,保存每个短语的起始位置和文本,然后,如果找到任何短语,则在同一源字符串中查找否定,保存否定的结束位置。为了确保否定结束位置与短语起始位置相同,我们在每次否定之后捕获空白以及否定本身。
重复调用re模块中的函数是相当昂贵的。如果你说的话有很多文字,你可能想要批量处理,例如在某些源字符串上使用'non-matching-string'.join()
。
import re
from collections import defaultdict
import csv
def read_csv(fname):
with open(fname, 'r') as csvfile:
result = list(csv.reader(csvfile))
return result
df_negations = read_csv('negations.csv')[1:]
df_phrases = read_csv('phrases.csv')[1:]
df_book = read_csv('test.csv')[1:]
negations = (str(row[0]) for row in df_negations)
phrases = (str(re.escape(row[1])) for row in df_phrases)
# Add a word to the negation pattern so it overlaps the
# next group.
negation_pattern = r"\b((?:%s)\W+)" % '|'.join(negations)
phrase_pattern = r"\b(%s)\b" % '|'.join(phrases)
counts = defaultdict(int)
for row in df_book:
normed = re.sub(r'[^\sa-zA-Z0-9]', '', row[0]).lower().strip()
# Find the location and text of any matching good groups
phrases = [(x.start(), x.group()) for x in
re.finditer(phrase_pattern, normed)]
if not phrases:
continue
# If we had matches, find the (start, end) locations of matching bad
# groups
negated = set(x.end() for x in re.finditer(negation_pattern, normed))
for start, text in phrases:
if start not in negated:
counts[text] += 1
else:
print("%r negated and ignored" % text)
for pattern, count in sorted(counts.items()):
print(count, pattern)