2017-05-08 78 views
2

我有一個的大數據幀控股用戶映射(索引)項的計數(列):如何矢量化包含自定義分組的熊貓計算?

users_items = pd.DataFrame(np.array([[0, 1, 1, 0],  # user 0 
            [1, 0, 0, 0],  # user 1 
            [5, 0, 0, 9],  # user 2 
            [0, 3, 5, 0],  # user 3 
            [0, 2, 2, 0],  # user 4 
            [7, 0, 0, 1],  # user 5 
            [3, 5, 0, 4]]), # user 6 
          columns=list('ABCD')) 

對於每一個用戶,我想找到所有具有非零計數至少相同的用戶物品和總數。因此對於用戶1,這將是用戶1,2,5和6,並且計數的總和等於[16, 5, 0, 14]。這可以用於根據「類似」用戶獲得的項目向用戶建議新項目。

這天真實現使用簽名作爲一個正則表達式來過濾出相關行和一個循環遍歷所有簽名:

def create_signature(request_counts): 
    return ''.join('x' if count else '.' for count in request_counts) 

users_items['signature'] = users_items.apply(create_signature, axis=1).astype('category') 

current_items = users_items.groupby('signature').sum() 

similar_items = pd.DataFrame(index=current_items.index, 
          columns=current_items.columns) 

for signature in current_items.index: 
    row = current_items.filter(regex=signature, axis='index').sum() 
    similar_items.loc[signature] = row 

結果是:

  A B C D 
signature    
.xx.  0 6 8 0 
x...  16 5 0 14 
x..x  15 5 0 14 
xx.x  3 5 0 4 

該作品很好,但對於由100k用戶和大約600個項目組成的實際數據集來說太慢了。生成簽名只需要10秒,但是在所有(40k)簽名上循環需要幾個小時。

向量化循環應該會帶來巨大的性能提升,但是我對熊貓的使用經驗有限,所以我不確定如何去做。甚至可以矢量化這種類型的計算?也許使用口罩?

+0

爲什麼有這個例子只有4個簽名?你是否需要其他組合,如.x ..,。xxx,x.xx等?爲什麼選擇這4個? – Allen

+0

@Allen簽名的集合只是來自users_items數據框中發生的任何數據。並非所有可能的簽名都會發生。 –

+0

so'x ...'應該是所有行的總和,它是其簽名的子集 –

回答

0

取而代之的是string的簽名,你可以使用一個frozenset

​​

另一種是

def create_signature(request_counts): 
    return frozenset(request_counts.replace({0: None}).dropna().index) 

我沒有足夠的大,看一個人是否是比速度更快的數據集其他。

如果有重複列,插入前.index

reset_index()電話本可以讓你vectorise你的過濾器到底

for signature in current_items.index: 
    row = current_items[signature <= current_items.index].sum() 
    similar_items.loc[signature] = row 

結果

signature     A B C D 
frozenset({'B', 'C'})  0 6 8 0 
frozenset({'A'})   16 5 0 14 
frozenset({'A', 'D'})  15 5 0 14 
frozenset({'B', 'A', 'D'}) 3 5 0 4 
+0

我會認爲使用frozensets(我想自己有點陣列)而不是字符串簽名會快得多。不幸的是,生成凍結​​簽名需要更長的時間(2分鐘與10秒)。這就是說,使用fronzesets循環只需要6個小時而不是8個,所以這裏有一個明顯的改進。不過,我認爲只有向量化for循環才能夠加速這個操作。 –

+0

for循環仍然需要與字符串1一樣長,因爲我期望'set'比較比'regex'更快。位陣列可能會更快,我提交我的評論後,我做了 –

+0

。我現在更新了它。 –