2011-01-10 48 views
0

我有以下功能:化功能的使用字典和Zip()

def filetxt(): 
    word_freq = {} 
    lvl1  = [] 
    lvl2  = [] 
    total_t = 0 
    users  = 0 
    text  = [] 

    for l in range(0,500): 
     # Open File 
     if os.path.exists("C:/Twitter/json/user_" + str(l) + ".json") == True: 
      with open("C:/Twitter/json/user_" + str(l) + ".json", "r") as f: 
       text_f = json.load(f) 
       users = users + 1 
       for i in range(len(text_f)): 
        text.append(text_f[str(i)]['text']) 
        total_t = total_t + 1 
     else: 
      pass 

    # Filter 
    occ = 0 
    import string 
    for i in range(len(text)): 
     s = text[i] # Sample string 
     a = re.findall(r'(RT)',s) 
     b = re.findall(r'(@)',s) 
     occ = len(a) + len(b) + occ 
     s = s.encode('utf-8') 
     out = s.translate(string.maketrans("",""), string.punctuation) 


     # Create Wordlist/Dictionary 
     word_list = text[i].lower().split(None) 

     for word in word_list: 
      word_freq[word] = word_freq.get(word, 0) + 1 

     keys = word_freq.keys() 

     numbo = range(1,len(keys)+1) 
     WList = ', '.join(keys) 
     NList = str(numbo).strip('[]') 
     WList = WList.split(", ") 
     NList = NList.split(", ") 
     W2N = dict(zip(WList, NList)) 

     for k in range (0,len(word_list)): 
      word_list[k] = W2N[word_list[k]] 
     for i in range (0,len(word_list)-1): 
      lvl1.append(word_list[i]) 
      lvl2.append(word_list[i+1]) 

我已經使用Profiler來發現它似乎是最大的CPU時間都花在zip()功能和joinsplit代碼的一部分,我期待看看是否有任何方式我忽略了我可能會清理代碼以使其更加優化,因爲最大的滯後似乎是我如何使用字典和zip()功能。任何幫助,將不勝感激謝謝!

p.s.這個函數的基本目的是我加載的文件中包含20個左右的推文,所以我最有可能最終會通過這個函數發送大約20k到50k個文件。輸出結果是我在推文中產生了所有不同單詞的列表,然後是哪些單詞鏈接到什麼,例如:

1 "love" 
2 "pasa" 
3 "mirar" 
4 "ants" 
5 "kers" 
6 "morir" 
7 "dreaming" 
8 "tan" 
9 "rapido" 
10 "one" 
11 "much" 
12 "la" 
... 
10 1 
13 12 
1 7 
12 2 
7 3 
2 4 
3 11 
4 8 
11 6 
8 9 
6 5 
9 20 
5 8 
20 25 
8 18 
25 9 
18 17 
9 2 
... 

回答

2

認爲你想要的東西,如:

import string 
from collections import defaultdict 
rng = xrange if xrange else range 

def filetxt(): 
    users  = 0 
    total_t = 0 
    occ  = 0 

    wordcount = defaultdict(int) 
    wordpairs = defaultdict(lambda: defaultdict(int)) 
    for filenum in rng(500): 
     try: 
      with open("C:/Twitter/json/user_" + str(filenum) + ".json",'r') as inf: 
       users += 1 
       tweets = json.load(inf) 
       total_t += len(tweets) 

       for txt in (r['text'] for r in tweets): 
        occ += txt.count('RT') + txt.count('@') 
        prev = None 
        for word in txt.encode('utf-8').translate(None, string.punctuation).lower().split(): 
         wordcount[word] += 1 
         wordpairs[prev][word] += 1 
         prev = word 
     except IOError: 
      pass 
+0

非常感謝我基本上從你和@milkypostman拿走了一些,但如果有人因爲某種原因尋找一個較短的答案,我會將其標記爲答案。另外我犯的最大錯誤是調用`W2N = dict(zip(WList,NList))`,它每循環一遍又一遍地製作一個更大更大的字典,並且浪費了cpu時間。解決的辦法是把它放在循環之外。過去需要5分鐘的1000個文件現在需要0.5秒左右的時間。 – eWizardII 2011-01-10 08:22:41

0

有幾件事。這些線條對我來說很奇怪放在一起時:

WList = ', '.join(keys) 
<snip> 
WList = WList.split(", ") 

那應該是Wlist = list(keys)

您確定要優化此?我的意思是,它真的很慢,它值得你花時間?最後,對腳本應該做什麼的描述會很棒,而不是讓我們從代碼中解密它:)

+0

謝謝,我會添加一個描述 - 這個問題是我打電話遇到像20K此功能 - 50k文件,每個文件包含約20個文本字符串或20個推文。所以如果我有1000個文件,那需要大約5分鐘的時間來運行。 – eWizardII 2011-01-10 04:02:25

1

我希望你不要介意我冒昧地修改你的代碼給我的東西更可能寫。

from itertools import izip 
def filetxt(): 
    # keeps track of word count for each word. 
    word_freq = {} 
    # list of words which we've found 
    word_list = [] 
    # mapping from word -> index in word_list 
    word_map = {} 
    lvl1  = [] 
    lvl2  = [] 
    total_t = 0 
    users  = 0 
    text  = [] 

    ####### You should replace this with a glob (see: glob module) 
    for l in range(0,500): 
     # Open File 
     try: 
      with open("C:/Twitter/json/user_" + str(l) + ".json", "r") as f: 
       text_f = json.load(f) 
       users = users + 1 
       # in this file there are multiple tweets so add the text 
       # for each one. 
       for t in text_f.itervalues(): 
        text.append(t) ## CHECK THIS 
     except IOError: 
      pass 

    total_t = len(text) 
    # Filter 
    occ = 0 
    import string 
    for s in text: 
     a = re.findall(r'(RT)',s) 
     b = re.findall(r'(@)',s) 
     occ += len(a) + len(b) 
     s = s.encode('utf-8') 
     out = s.translate(string.maketrans("",""), string.punctuation) 


     # make a list of words that are in the text s 
     words = s.lower().split(None) 

     for word in word_list: 
      # try/except is quicker when we expect not to miss 
      # and it will be rare for us not to have 
      # a word in our list already. 
      try: 
       word_freq[word] += 1 
      except KeyError: 
       # we've never seen this word before so add it to our list 
       word_freq[word] = 1 
       word_map[word] = len(word_list) 
       word_list.append(word) 


     # little trick to get each word and the word that follows 
     for curword, nextword in zip(words, words[1:]): 
      lvl1.append(word_map[curword]) 
      lvl2.append(word_map[nextword]) 

現在要做的是給你以下。 lvl1會給你一個對應於word_list中單詞的數字列表。因此word_list[lvl1[0]]將成爲您處理的第一條推文中的第一個詞。 lvl2[0]將會是lvl1[0]之後的單詞的索引,所以你可以說,world_list[lvl2[0]]follows word_list[lvl1[0]]這個單詞。此代碼基本上維護word_mapword_listword_freq,因爲它構建了此代碼。

請注意,這樣你才這樣做的,特別是你正確創建W2N工作的方式。字典不維護秩序。有序字典正在3.1版中,但現在只是忘記了它。基本上,當你在做word_freq.keys()時,每當你添加一個新單詞時就會改變,所以沒有一致性。看到這個例子,

>>> x = dict() 
>>> x[5] = 2 
>>> x 
{5: 2} 
>>> x[1] = 24 
>>> x 
{1: 24, 5: 2} 
>>> x[10] = 14 
>>> x 
{1: 24, 10: 14, 5: 2} 
>>> 

所以5曾經是第二個,但現在是第三個。

我也更新它使用0索引,而不是1索引。我不知道你爲什麼使用range(1, len(...)+1)而不僅僅是range(len(...))

無論如何,您應該遠離思考for循環的傳統意義上的C/C++/Java,你可以循環使用數字。你應該考慮到,除非你需要一個索引號,那麼你不需要它。

經驗法則:如果您需要索引,您可能需要該索引處的元素,並且您應該使用enumerateLINK

希望這有助於...

+0

在閱讀了關於字典的討論之後,我意識到我犯的最糟糕的錯誤是在循環中多次調用`W2N = dict(zip(WList,NList)),所以非常感謝! – eWizardII 2011-01-10 08:24:13