Python 2.7 计算文件中的字符串,一些单字,一些完整的句子
我想计算文件中某些单词和名称的出现次数。下面的代码错误地将Python 2.7 计算文件中的字符串,一些单字,一些完整的句子,python-2.7,text,counter,word-count,Python 2.7,Text,Counter,Word Count,我想计算文件中某些单词和名称的出现次数。下面的代码错误地将鱼和薯条计数为一箱鱼和一箱薯条,而不是一箱鱼和薯条 ngh.txt = 'test file with words fish, steak fish chips fish and chips' import re from collections import Counter wanted = ''' "fish and chips" fish chips steak ''' cnt = Counter() words = re.fin
鱼和薯条
计数为一箱鱼
和一箱薯条
,而不是一箱鱼和薯条
ngh.txt = 'test file with words fish, steak fish chips fish and chips'
import re
from collections import Counter
wanted = '''
"fish and chips"
fish
chips
steak
'''
cnt = Counter()
words = re.findall('\w+', open('ngh.txt').read().lower())
for word in words:
if word in wanted:
cnt[word] += 1
print cnt
输出:
Counter({'fish': 3, 'chips': 2, 'and': 1, 'steak': 1})
我想要的是:
Counter({'fish': 2, 'fish and chips': 1, 'chips': 1, 'steak': 1})
(理想情况下,我可以得到如下输出:
fish: 2
fish and chips: 1
chips: 1
steak: 1
)因此此解决方案适用于您的测试数据(以及测试数据中添加的一些术语,只是为了更全面),尽管它可能会得到改进 它的关键是在单词列表中找到“and”的出现,然后用一个复合词替换“and”及其相邻词(将相邻词与“and”连接起来),并将其与“and”的副本一起添加到列表中 我还将“通缉”字符串转换为一个列表,以将“炸鱼薯条”字符串作为一个不同的项处理
import re
from collections import Counter
# changed 'wanted' string to a list
wanted = ['fish and chips','fish','chips','steak', 'and']
cnt = Counter()
words = re.findall('\w+', open('ngh.txt').read().lower())
for word in words:
# look for 'and', replace it and neighbours with 'comp_word'
# slice, concatenate, and append to make new words list
if word == 'and':
and_pos = words.index('and')
comp_word = str(words[and_pos-1]) + ' and ' +str(words[and_pos+1])
words = words[:and_pos-1] + words[and_pos+2:]
words.append(comp_word)
words.append('and')
for word in words:
if word in wanted:
cnt[word] += 1
print cnt
文本的输出将是:
Counter({'fish':2, 'and':1, 'steak':1, 'chips':1, 'fish and chips':1})
正如上面的评论所指出的,不清楚为什么您希望/期望理想产量中的鱼产量为2,薯条产量为2,鱼和薯条产量为1。我假设这是一个输入错误,因为上面的输出有
'chips':1
我建议使用两种算法来处理任何模式和任何文件。
第一个算法的运行时间与(文件中的字符数)*模式数成比例
1> 对于每个模式,搜索所有模式并创建超级模式列表。这可以通过将一个模式(如“cat”)与要搜索的所有模式进行匹配来实现
patterns = ['cat', 'cat and dogs', 'cat and fish']
superpattern['cat'] = ['cat and dogs', 'cat and fish']
2> 在文件中搜索“cat”,假设结果是cat\u计数
3> 现在搜索文件中每个“猫”的晚餐模式,并获取它们的计数
for (sp in superpattern['cat']) :
sp_count = match sp in file.
cat_count = cat_count - sp
这是一个普遍的解决办法,即暴力。如果我们将模式安排在一个Trie中,应该能够得到一个线性时间解。
根-->f-->i-->s-->h-->a等。
现在,当你们在鱼的h,你们并没有得到一个a,增加鱼的数量,然后去根。如果你得了a,继续。任何时候,当您得到一些不期望的东西时,增加最近找到的模式的计数,并转到根节点或其他节点(最长的匹配前缀是该其他节点的后缀)。这是Aho Corasick算法,您可以在维基百科或以下网址查找:
此解决方案与文件中的字符数成线性关系。定义: 所需项目:在文本中搜索的字符串 要计算所需项目的数量,而不在较长的所需项目中重新计算它们,请首先计算每个项目在字符串中出现的次数。接下来,从最长到最短遍历所需项目,当遇到出现在较长所需项目中的较小所需项目时,从较短项目中减去较长项目的结果数。例如,假设您想要的项目是“a”、“a b”和“a b c”,而您的文本是“a/a/a b/a b c”。搜索每一个单独的结果:{“a”:4,“ab”:2,“abc”:1}。期望的结果是:{“abc”:1,“abb”:(abc)-(abc)=2-1=1,“abc”)-(abc)-(abc)-(abc)=4-1-1=2}
def get_word_counts(text, wanted):
counts = {}; # The number of times a wanted item was read
# Dictionary mapping word lengths onto wanted items
# (in the form of a dictionary where keys are wanted items)
lengths = {};
# Find the number of times each wanted item occurs
for item in wanted:
matches = re.findall('\\b' + item + '\\b', text);
counts[item] = len(matches)
l = len(item) # Length of wanted item
# No wanted item of the same length has been encountered
if (l not in lengths):
# Create new dictionary of items of the given length
lengths[l] = {}
# Add wanted item to dictionary of items with the given length
lengths[l][item] = 1
# Get and sort lenths of wanted items from largest to smallest
keys = lengths.keys()
keys.sort(reverse=True)
# Remove overlapping wanted items from the counts working from
# largest strings to smallest strings
for i in range(1,len(keys)):
for j in range(0,i):
for i_item in lengths[keys[i]]:
for j_item in lengths[keys[j]]:
#print str(i)+','+str(j)+': '+i_item+' , '+j_item
matches = re.findall('\\b' + i_item + '\\b', j_item);
counts[i_item] -= len(matches) * counts[j_item]
return counts
以下代码包含测试用例:
tests = [
{
'text': 'test file with words fish, steak fish chips fish and '+
'chips and fries',
'wanted': ["fish and chips","fish","chips","steak"]
},
{
'text': 'fish, fish and chips, fish and chips and burgers',
'wanted': ["fish and chips","fish","fish and chips and burgers"]
},
{
'text': 'fish, fish and chips and burgers',
'wanted': ["fish and chips","fish","fish and chips and burgers"]
},
{
'text': 'My fish and chips and burgers. My fish and chips and '+
'burgers',
'wanted': ["fish and chips","fish","fish and chips and burgers"]
},
{
'text': 'fish fish fish',
'wanted': ["fish fish","fish"]
},
{
'text': 'fish fish fish',
'wanted': ["fish fish","fish","fish fish fish"]
}
]
for i in range(0,len(tests)):
test = tests[i]['text']
print test
print get_word_counts(test, tests[i]['wanted'])
print ''
结果如下:
test file with words fish, steak fish chips fish and chips and fries
{'fish and chips': 1, 'steak': 1, 'chips': 1, 'fish': 2}
fish, fish and chips, fish and chips and burgers
{'fish and chips': 1, 'fish and chips and burgers': 1, 'fish': 1}
fish, fish and chips and burgers
{'fish and chips': 0, 'fish and chips and burgers': 1, 'fish': 1}
My fish and chips and burgers. My fish and chips and burgers
{'fish and chips': 0, 'fish and chips and burgers': 2, 'fish': 0}
fish fish fish
{'fish fish': 1, 'fish': 1}
fish fish fish
{'fish fish fish': 1, 'fish fish': 0, 'fish': 0}
你所期望的真是令人困惑。如果你想计算所有出现的鱼,它应该是3。如果要排除它,它应该是2。然而,如果你排除了出现在其他通缉物品中的通缉物品,鱼应该是2,薯条应该是1。不过,你有鱼2份,薯条2份。我很抱歉,戴夫,我已经编辑了这个问题。谢谢,并为拼写错误道歉!不用担心,最后一切都安排好了。希望这个答案对你有用。我不确定我是否明白。你的意思是我必须在运行程序之前手动计算单词的频率吗?是的,但是你可以使用相同的模式匹配来完成。但是,我无法给出一个通用公式,说明如何使用它来获得结果。太棒了。非常感谢你,戴夫。