2016-11-16 3 views
1

私は3列のデータフレームを持っています。 Col 1はストリング注文番号、Col 2は整数日、Col 3は製品名です。 これを行列に変換して、各行が固有の注文/日の組み合わせを表し、各列がその組み合わせの製品名の存在を示す1/0を表す行列に変換したいと考えています。pandasデータフレームから複合キーを使用したスパースキーアイテムマトリックスへの変換

これまでのアプローチでは、製品辞書と、注文番号&日の複合キーを使用した辞書を使用しています。 行列のビットを1にフリップするために元のデータフレームを反復処理する最後のステップはsloooowです。マトリックスの場合、363K×331のサイズと約97%の希薄さの10分のように。

私は考慮すべき別のアプローチがありますか?

例えば、

ord_nb day prod 
1 1 A 
1 1 B 
1 2 B 
1 2 C 
1 2 D 

は私のアプローチは、オーダー/日のペアの辞書を作成することであった

A B C D 
1 1 0 0 
0 1 1 1 

なる:

ord_day_dict = {} 
print("Making a dictionary of ord-by-day keys...") 
gp = df.groupby(['day', 'ord']) 
for i,g in enumerate(gp.groups.items()): 
    ord_day_dict[g[0][0], g[0][1]] = i 

私はインデックスrepresentionを追加元のデータフレーム:

df['ord_day_idx'] = 0 #Create a place holder column 
for i, row in df.iterrows(): #populate the column with the index 
    df.set_value(i,'ord_day_idx',ord_day_dict[(row['day'], row['ord_nb'])]) 

私はその後、私のORD /日Xユニークな製品のサイズ行列を初期化します。

n_items = df.prod_nm.unique().shape[0] #unique number of products 
n_ord_days = len(ord_day_dict) #unique number of ord-by-day combos 
df_fac_matrix = np.zeros((n_ord_days, n_items), dtype=np.float64)#-1) 

私は辞書を経由してインデックスに文字列から私のプロダクトを変換:

prod_dict = dict() 
i = 0 
for v in df.prod: 
    if v not in prod_dict: 
     prod_dict[v] = i 
     i = i + 1 

そして最後に元のデータフレームを反復して、特定の日の特定の注文に特定の製品が含まれている行列を1に設定します。ここで

for line in df.itertuples(): 
    df_fac_matrix[line[4], line[3]] = 1.0 #in the order-by-day index row and the product index column of our ord/day-by-prod matrix, mark a 1 

答えて

1

はここで出力として配列持つようにnumpyのベースのアプローチだ -

a = df[['ord_nb','day']].values.astype(int) 
row = np.unique(np.ravel_multi_index(a.T,a.max(0)+1),return_inverse=1)[1] 
col = np.unique(df.prd.values,return_inverse=1)[1] 
out_shp = row.max()+1, col.max()+1 
out = np.zeros(out_shp, dtype=int) 
out[row,col] = 1 

は、3番目の列があると仮定したことに注意してください代わりに名前が'prd'であり、名前と組み込みの競合が発生しないようにしてください。パフォーマンスに焦点を当てた

考えられる改善 -

  • prdのみAから始まる単一文字の文字が含まれている場合は、我々は単にでcolを計算することができます:df.prd.values.astype('S1').view('uint8')-65

  • rownp.unique(a[:,0]*(a[:,1].max()+1) + a[:,1],return_inverse=1)[1]と計算することもできます。

保存メモリスパース配列を持つ:本当に巨大な配列では、私たちは、スパース行列としてそれらを格納することで、メモリを節約することができます。したがって、そのような疎行列を得るために、最終的な手順は次のようになり -

from scipy.sparse import coo_matrix 

d = np.ones(row.size,dtype=int) 
out_sparse = coo_matrix((d,(row,col)), shape=out_shp) 

サンプル入力、出力 -

In [232]: df 
Out[232]: 
    ord_nb day prd 
0  1 1 A 
1  1 1 B 
2  1 2 B 
3  1 2 C 
4  1 2 D 

In [233]: out 
Out[233]: 
array([[1, 1, 0, 0], 
     [0, 1, 1, 1]]) 

In [241]: out_sparse 
Out[241]: 
<2x4 sparse matrix of type '<type 'numpy.int64'>' 
    with 5 stored elements in COOrdinate format> 

In [242]: out_sparse.toarray() 
Out[242]: 
array([[1, 1, 0, 0], 
     [0, 1, 1, 1]]) 
2

あなたが試すことができます一つの選択肢である:

df.groupby(['ord_nb', 'day'])['prod'].apply(list).apply(lambda x: pd.Series(1, x)).fillna(0) 

#    A B C D 
#ord_nb day    
#  1 1 1.0 1.0 0.0 0.0 
#   2 0.0 1.0 1.0 1.0 
関連する問題