2012-04-27 341 views
1

我必須創建用戶和電視節目的鄰接列表,其中行是用戶,電視節目是列。如果用戶跟隨該電視節目,則矩陣中將有一個1,否則爲零。我已經從twitter上收集了這些信息。共有140個電視節目和約530000個獨特用戶。我使用下面的代碼生成矩陣,使用python:使用numpy縮小矩陣的大小

  • NoTvShows:所有的獨立用戶
  • collected_users:電視節目(IDS)
  • unique_user總數這是一個列表的列表。該子列表對應於電視節目並列出追隨者的ID。
for i in range(0,NoTvShows): 
    for every_user in unique_users: 
     if every_user in collected_users[i]: 
      matrix.append(1) 
     else: 
      matrix.append(0) 
    main_matrix.append(matrix) 
    matrix = [] 

the_matrix = zip(*main_matrix) 
simplejson.dump(the_matrix,fwrite) 
fwrite.close() 

當我嘗試在服務器上執行我的程序,它崩潰,因爲它採取了大量的時間和內存。我知道我可以使用numpy來減少矩陣的大小,然後用它來計算用戶之間的相似度。但是,我不確定如何在此代碼中編碼numpy並生成簡化矩陣。

我希望有人能指導我在這方面

謝謝

Richa

回答

6

稀疏矩陣(與suggested by @phg一樣)很好,因爲矩陣中的大多數條目可能都是0(假設大多數用戶只關注幾個電視節目)。

雖然可能更重要的是,你以非常低效的方式構建矩陣(製作大量的Python列表並複製它們),而不是僅僅將它們放置在一個很好的緊湊numpy數組中。此外,您花費大量時間搜索列表(使用in聲明),但這對於您的循環來說並不是必需的。

此代碼在follower列表中循環,並在user_ids字典中查找每個id的用戶#。你可以適應稀疏矩陣類非常普通(只要切換np.zerosscipy.sparse.coo_matrix,我認爲)。

user_ids = dict((user, i) for i, user in enumerate(unique_users)) 

follower_matrix = np.zeros(NoTvShows, len(unique_users), dtype=bool) 
for show_idx, followers in enumerate(collected_users): 
    for user in followers: 
     follower_matrix[show_idx, user_ids[user]] = 1 

一旦你的矩陣,你真的,真的不希望將其保存爲JSON,除非你有:它是數字矩陣真是浪費格式。 numpy.save是最好的,如果你只是在numpy中再次使用數據矩陣。 numpy.savetxt也可以工作,至少消除了括號和逗號,並且在寫入時可能會減少內存開銷。但是當你有一個0-1矩陣並且它是布爾數據類型時,numpy.save只需要每個矩陣元素一位,而numpy.savetxt需要兩個字節= 16位(一個ASCII碼'0''1'加空格或換行符),而json使用at至少三個字節,我認爲(逗號,空格,加上一些括號在每一行)。


您可能還在討論降維技術。這也是非常可能的;有很多技術可以通過某種PCA類型的技術,主題模型,或者基於羣集的方式來減少140維(向電視節目播放)的向量,從而降低維度。如果您的唯一值得關注的是構建矩陣需要很長時間,但這根本不會有幫助(因爲這些技術通常需要完整的原始矩陣,然後給出一個較低維的版本)。在這裏試試我的建議,如果它不夠好,嘗試一個稀疏矩陣,然後擔心減少數據的奇特方法(可能是通過學習數據子集的維數減少,然後構建其餘部分)。

+0

嘿,非常感謝!將嘗試實施您的建議。 – 2012-04-27 06:54:01

1

這是另一種方法,以防您感興趣。它假定您的用戶存儲順序,但它們可以是數字或字符串ID:

# The setup 
users = ['bob', 'dave', 'steve'] 
users = np.array(users) 
collected_users = [['bob'], ['dave'], ['steve', 'dave'], ['bob', 'steve', 'dave']] 
NoTvShows = len(collected_users) 

# The meat 
matrix = np.zeros((NoTvShows, len(users)), 'bool') 
for i, watches in enumerate(collected_users): 
    index = users.searchsorted(watches) 
    matrix[i, index] = 1 
+0

這正是我存儲數據的方式。謝謝! – 2012-04-27 18:56:19

+0

我不知道'searchsorted'一次處理多個值 - 非常方便。儘管如此,我認爲字典仍然可能會贏。 (我很好奇,所以我[挖到源](https://github.com/numpy/numpy/blob/master/numpy/core/src/multiarray/item_selection.c#L1498),它只是做獨立二進制搜索每一個,沒有什麼幻想,這種方式確實把這些循環放到C中,但是530,000仍然很大。) – Dougal 2012-04-27 20:42:03

+0

雅,我沒有時間看看哪個會更快。字典是驚人的,我只是想給一個更多的numpy,即方法。我想這個問題變成python for-loop的開銷超過了log(530,000)。 – 2012-04-27 21:31:05