簡體   English   中英

提高python算法的速度

[英]Improve speed of python algorithm

我已將 Sentiment140 數據集用於 twitter 進行情感分析

代碼:

從推文中獲取單詞:

tweet_tokens = []
[tweet_tokens.append(dev.get_tweet_tokens(idx)) for idx, item in enumerate(dev)]

從令牌中獲取未知單詞

words_without_embs = []
[[words_without_embs.append(w) for w in tweet if w not in word2vec] for tweet in tweet_tokens]
len(words_without_embs)

代碼的最后一部分,計算向量作為左右詞(上下文)的平均值

vectors = {} # alg
for word in words_without_embs:
  mean_vectors = []
  for tweet in tweet_tokens:
    if word in tweet:
      idx = tweet.index(word)
      try:
        mean_vector = np.mean([word2vec.get_vector(tweet[idx-1]), word2vec.get_vector(tweet[idx+1])], axis=0)
        mean_vectors.append(mean_vector)
      except:
        pass

    if tweet == tweet_tokens[-1]: # last iteration
      mean_vector_all_tweets = np.mean(mean_vectors, axis=0)
      vectors[word] = mean_vector_all_tweets

有 1058532 個字,這段代碼的最后一部分工作很慢,大約每分鍾 250 個字。

你如何提高這個算法的速度?

代碼緩慢的主要原因之一是檢查tweet_tokens每條推文的所有單詞(接近 100 萬個單詞)是否tweet_tokens 因此,您的實現的時間復雜度是1e6 * |tweet_tokens| .

1)第一次改進(減少搜索和比較)

但是,您可以通過先標記每條tweet ,然后找到單詞的索引來做得更好。 如果您在現有單詞上構建了一本字典,您可以從單詞字典中找到最多log(1e6) ~ 25比較的單詞標記的索引。 因此,在這種情況下,時間復雜度最多為25 * |tweet_tokens| . 因此,您可以將代碼的性能提高1e6/25 = 40000倍!

2) 第二次改進(減少 Word2Vec 計算)

此外,你總是在計算不同推文中同一個詞的向量。 因此,每個單詞的向量將被計算f倍, f是單詞在推文中的頻率。 一種合理的解決方案是將words_without_embs中所有單詞的向量計算一次(它可以是一個離線過程)。 然后,例如,根據單詞詞典中單詞的索引存儲所有這些向量(以某種方式根據單詞查詢快速找到它們)。 最終,只需從准備好的數據結構中讀取它以進行平均計算。 在這種情況下,除了 40000 倍的改進之外,您還可以通過推文中所有單詞頻率之和的系數來提高代碼的性能。

這看起來可以很好地與一些小的編輯並行。

  • if tweet == tweet_tokens[-1]:阻塞一個級別並刪除它的“if”語句,你能移動最后一個嗎? 這本身只會帶來輕微的速度提升,但是有了它,您可以更有效地並行化代碼。
  • 考慮使內部 for 循環成為自己的函數並通過多線程設置調用它。 (有關說明和示例,請參閱本站點上的ThreadPoolExecutor 和 thread_function()。)然后,您可以為單個機器上的每個處理器或分布式環境中的每個 VM 擁有一個單獨的線程。 這應該允許更有效的縮放。
  • 以上面@DarrylG 的評論為基礎,重構這些列表推導式以避免將 .append() 與現有列表一起使用。 .append() 比等效的列表理解要慢。 例如,將[tweet_tokens.append(dev.get_tweet_tokens(idx)) for idx, item in enumerate(dev)]更改為tweet_tokens = [dev.get_tweet_tokens(idx) for idx, item in enumerate(dev)]

處理未知單詞的更常見(並且可能更好)的策略包括:

  • 訓練/使用模型,如 FastText,可以為詞匯外 (OOV) 詞提供猜測向量
  • 獲取更多的訓練數據,因此可以從實際用法中學習更多未知詞的向量
  • 完全忽略生詞

您似乎決定通過對所有直接鄰居求平均值來為 OOV 詞合成新向量。 我不認為這會特別有效。 在詞向量的多種下游使用中,它只是傾向於過重詞的上下文中的鄰居——這也可以通過完全忽略未知詞來非常簡單/廉價地實現。

但考慮到您想要做什么,最好的方法是在標識words_without_embs的同一遍期間收集相鄰的單詞。

例如,使words_without_embs成為一個dict (或者可能是一個DefaultDict ),其中每個鍵是一個需要向量的詞,每個值是您迄今為止找到的所有相鄰詞的list

然后, tweet_tokens一個循環將用需要向量的詞的填充words_without_embs ,同時用目前看到的所有相鄰詞填充這些

然后,對words_without_embs鍵的最后一次循環將簡單地獲取現有的相鄰詞列表進行平均。 (不再多次通過tweet_tokens 。)

但同樣:所有這些工作可能不會勝過簡單地刪除未知單詞的基線做法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM