2017-06-29 52 views
3

我正在對由於PDF到txt轉換錯誤,某些時候合併在一起的文本進行文本分析。所以,我想匹配字符串,而不是匹配單詞。Python 3.5 - 獲取計數器報告零頻率項目

例如,我有字符串:

mystring='The lossof our income made us go into debt but this is not too bad as we like some debts.' 

我搜索

key_words=['loss', 'debt', 'debts', 'elephant'] 

輸出應該是這樣的形式:

Filename Debt Debts Loss Elephant 
mystring 2 1  1 0 

我作品中的代碼好吧,除了一些小故障:1)它沒有報告零頻詞的頻率(所以'大象'不會出現在輸出t:2)key_words中單詞的順序似乎很重要(即。我有時會爲「債務」和「債務」分別得到1個計數,有時它只會報告2個「債務」,而且「債務沒有報告。如果我設法將變量名稱「打印」到數據集中,我可以接受第二點...但不知道如何。

下面是相關的代碼。謝謝! PS。不用說,它不是最優雅的一段代碼,但我正在慢慢學習。

bad=set(['debts', 'debt']) 

csvfile=open("freq_10k_test.csv", "w", newline='', encoding='cp850', errors='replace') 
writer=csv.writer(csvfile) 
for filename in glob.glob('*.txt'): 

    with open(filename, encoding='utf-8', errors='ignore') as f: 
     file_name=[] 
     file_name.append(filename) 

     new_review=[f.read()] 
     freq_all=[] 
     rev=[] 

     from collections import Counter 

     for review in new_review: 
     review_processed=review.lower() 
     for p in list(punctuation): 
      review_processed=review_processed.replace(p,'') 
      pattern = re.compile("|".join(bad), flags = re.IGNORECASE) 
      freq_iter=collections.Counter(pattern.findall(review_processed))   

     frequency=[value for (key,value) in sorted(freq_iter.items())] 
     freq_all.append(frequency) 
     freq=[v for v in freq_all] 

    fulldata = [ [file_name[i]] + freq for i, freq in enumerate(freq)] 

    writer=csv.writer(open("freq_10k_test.csv",'a',newline='', encoding='cp850', errors='replace')) 
    writer.writerows(fulldata) 
    csvfile.flush() 

回答

1

您只需預先初始化計數器,這樣的事情:

freq_iter = collections.Counter() 
freq_iter.update({x:0 for x in bad}) 
freq_iter.update(pattern.findall(review_processed)) 

一關於的好消息是你實際上不需要預先初始化它 - 你可以做c = Counter(); c['key'] += 1,但是如果你願意的話,沒有什麼能阻止你將某些值初始化爲0。

對於debt/debts的事情 - 這只是一個沒有明確指出的問題。你在做什麼想要這種情況下做的代碼?如果您希望它匹配匹配的最長模式,則需要將列表最長排序,這將解決它。如果你想同時報告,你可能需要做多個搜索並保存所有結果。

已更新,以增加一些信息,爲什麼它找不到debts:這與正則表達式findall其他更多。 re.findall總是尋找最短的比賽,而且一旦它找到一個,它不包括在隨後的比賽:

In [2]: re.findall('(debt|debts)', 'debtor debts my debt') 
Out[2]: ['debt', 'debt', 'debt'] 

如果你真的想找到每一個字的所有情況下,你需要做的他們分別:

In [3]: re.findall('debt', 'debtor debts my debt') 
Out[3]: ['debt', 'debt', 'debt'] 

In [4]: re.findall('debts', 'debtor debts my debt') 
Out[4]: ['debts'] 

但是,也許你真正需要的是。在這種情況下,使用\b運營商需要一個字符:

In [13]: re.findall(r'\bdebt\b', 'debtor debts my debt') 
Out[13]: ['debt'] 

In [14]: re.findall(r'(\b(?:debt|debts)\b)', 'debtor debts my debt') 
Out[14]: ['debts', 'debt'] 

我不知道這是否是你想要的或不...在這種情況下,它能夠區分debtdebts正確,但它錯過了debtor,因爲它只匹配一個子字符串,我們不問它。

根據您的使用情況,您可能需要查看詞幹文本......我相信在nltk中有一個非常簡單(僅用於一次,因此我不會嘗試發佈示例。 ..這個問題Combining text stemming and removal of punctuation in NLTK and scikit-learn可能是有用的),它應該減少debt,debtsdebtor所有到相同的根詞debt,併爲其他單詞做類似的事情。這可能會或可能不會有幫助;我不知道你在做什麼。

+0

但是,在計數器中使用零值時要小心。如果你使用計數器進行一些算術運算,那麼[鍵和值可以默默丟失](https://stackoverflow.com/q/21887125/674039)。 – wim

+0

謝謝。我必須通讀完整的清單,看看我是否保留單數/複數。爲了我自己的利益,爲什麼Counter沒有發現列表中所有字符串的出現,但只保持最短(即「債務」與「債務」)? –

+0

謝謝@wim,很高興知道。 –

1

像你想:

mystring='The lossof our income made us go into debt but this is not too bad as we like some debts.' 
key_words=['loss', 'debt', 'debts', 'elephant'] 
for kw in key_words: 
    count = mystring.count(kw) 
    print('%s %s' % (kw, count)) 

或者單詞:

from collections import defaultdict 
words = set(mystring.split()) 
key_words=['loss', 'debt', 'debts', 'elephant'] 
d = defaultdict(int) 
for word in words: 
    d[word] += 1 

for kw in key_words: 
    print('%s %s' % (kw, d[kw])) 
+1

在第2部分中,您可以將'dict()'更改爲'defaultdict(int)'以擺脫內部'if'語句。 – woodpav

+0

已編輯!我不知道這個伎倆,有用! ;) –

+0

謝謝。我一回到我的電腦就會測試這個。 –