2016-06-19 31 views
0

希望有人能幫到這裏嗎?我的代碼效率低下還是我的任務很難?

我已經寫了一些代碼來執行查找任務,並且需要很長時間才能完成 - 遠比看起來要長。出於保密原因,我無法描述確切的任務,但我可以給出一個直接類似的問題。

比方說,我有一個數據庫,其中包含一個單詞列表和一組與這些單詞相對應的值。說,顏色和多少這些顏色是喜歡的。

現在,我有一個文本,我想將本文中的所有單詞與我的顏色數據庫進行比較,如果匹配存在,我從數據庫中提取「喜歡」評分並記錄下來。當文本中的所有單詞與數據庫匹配(或不匹配)時,「喜歡」評分的總和就是我的輸出。

與我寫的代碼相當於下面的代碼,它對我給出的玩具示例很有用。但是,我的實際問題包含一個40k條目的數據庫,文本通常包含約500個單詞;文本中的大部分單詞都將在數據庫中。當我運行它時,需要數小時才能執行。我知道,將500個單詞與40k個條目的數據庫匹配意味着大約20m比較的數量級。 小時

任何人都可以建議我是否在有限的硬件上做計算密集型問題,或者我的代碼只是大量低效?

謝謝!

import pandas as pd 
import nltk as nltk 

####### Creates toy data to test code on ### 

colour = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'] 
values = [1,2,3,4,5,6,7] 

df1 = pd.DataFrame({'colour': ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']}) 

df2 = pd.DataFrame({'value': [1,2,3,4,5,6,7]}) 

dfs = [df1, df2] 

###### Code proper begins below 

data = pd.concat(dfs, axis = 1) ######## Dataframe 


#### Sample words 
words = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet', 'cyan', 'white', 'black', 'pink', 'grey', 'scarlet'] 


#### Lists into which words are put post-analysis 
rating = 0 
rated = [] 
unrated = [] 

####### Code 

for i in words: 
    for j in range(len(data['colour'])): 
     if i == data['colour'][j]: 
      rating = rating + data['value'][j] 
      rated.append(i) 
      break 
     elif i not in unrated and i not in data.values: ### Ensures each unrated word is entered only once. 
      unrated.append(i) 
+2

有效的解決方案將不會迭代。我建議尋找哈希樹或類似結構。無論大小如何,地圖查找都接近恆定時間是有原因的。 –

+2

......這就是說:這是設計效率低下的問題,而不是實施問題。如果你想使用非常擅長這種工具的工具,可以考慮創建一個適當索引的SQL數據庫嗎?有些數據庫支持全文索引,這尤其適用於apropos。 –

+0

夠公平的,儘管我現在還停留在Python中,所以SQL解決方案將無法工作。不過,我會研究哈希樹。 – Lodore66

回答

0

讓我們先從一些數學......如果你在你的DB 40000項,您需要檢查500個字(無特別明顯的規則),您將需要執行20000000個比較。這不是一項小任務。其次,假設您正在比較字符串(單詞),您還在做一些CASE操作(例如,確保「RED」,「Red」,「REd」,「ReD」,...,「red」被認爲是相同的值)。

因此,總而言之,您應該預計至少需要幾秒鐘的時間。但不是HOURS(除非你使用8086處理器:-))。

最後,您的代碼似乎是不完整的,因此無法檢查。

+0

是的,我知道問題的嚴重性:你會看到我已經在我原來的帖子中提到了2000萬的數字。儘管代碼不完整? 'rating'變量返回我想要的值;我忽略了哪些是相關的? – Lodore66

0

好的,我從離線的人那裏得到了一些建議,這在這裏造成了很大的變化;對於有類似問題的人來說,這可能會很有用。看來我最大的瓶頸在於:

elif i not in unrated and i not in data.values: 

這是因爲data.values是一個數組,它需要時間來搜索。創建變量

words = set(data1['Word'].values) 

,輪流陣列成一組,並把該進入循環,而不是在陣列的下降執行時間爲1小時+至約3分鐘。這還是很慢,但比它好。

2

您需要對關鍵字建立索引,以便在O(1)時間內查找文本中的每個單詞。如果數據集可以裝入內存(並用40K的話,應該沒問題),也可以是這樣簡單:

sentiment_index = dict(zip(colour, values)) 
rated = set() 

for i in words: 
    i = i.lower() 
    rating += sentiment_index.get(i, 0) 
    rated.add(i) 

你也可以寫rating += sentiment_index[i],這是同樣快。但是,那麼你需要一個存在檢查,我通過使用默認值get()來避免。當然,我添加了一組評價詞。如果您確實需要將查找委託給數據庫,請在數據框中添加索引以加快查找速度。

+0

這真的很好,它直接影響到問題的核心。非常感謝你!我會很多地使用這個代碼,所以你在這裏做了很大的改變! – Lodore66

+1

很高興喜歡它。它可能會更快一些,但是如果你一次創建集合「額定」,就像你的自我回答一樣;我沒有這樣做,因爲我不知道你的實際代碼中還有什麼。但是你真正的問題是長列表的重複掃描,所以你如何建立這個集合比較小。 (仍然:運行一些時間測試併爲自己找出答案。) – alexis