2017-05-03 4 views
1

私はこのようなデータセットを有する型配列(フロート)の一つの列にfloat型の複数の列を組み合わせる:ここすばやく

df = pd.DataFrame({ 
    "333-0": [123,123,123], 
    "5985-0.0": [1,2,3], 
    "5985-0.1":[1,2,3], 
    "5985-0.2":[1,2,3] 
    }, 
    index = [0,1,2]) 

を、我々は3つの列、第一、第二及び第三のフロートを表す["5985-0.0", "5985-0.1", "5985-0.2"]を有します物語5985-0の読み取り - すなわち.xは配列インデックスを表します。

私は複数の列を取り、私はこのように行うことができますフロートのリストのいくつかの種類を含む単一の列5985-0にそれらを崩壊したい:私は、SQLとして保存することができます

srccols = ["5985-0.0", "5985-0.1", "5985-0.2"] 
df["5985-0"] = df[srccols].apply(tuple, axis=1) 
df.dropna(srccols, axis=1) 

    333-0  5985-0 
0 123 (1, 1, 1) 
1 123 (2, 2, 2) 
2 123 (3, 3, 3) 

配列の列を持つテーブル。

ただし、適用(タプル)は非常に遅いです。複数の列を1つにまとめる、より速く、もっと慣用的なパンダの方法がありますか?

(「正規化された」と言う最初の人はダウンボートを取得します)。

答えて

1

マイ・チョイス・
私はfilterjoin、およびapply(tuple, 1)

を使用して、列

thing = '5985-0' 
cols = ['5985-0.0', '5985-0.1', '5985-0.2'] 
k = len(cols) 
v = df.values 
l = [v[:, df.columns.get_loc(c)].tolist() for c in cols] 
s = pd.Series(list(zip(*l)), name=thing) 
df.drop(cols, 1).join(s) 

    333-0  5985-0 
0 123 (1, 1, 1) 
1 123 (2, 2, 2) 
2 123 (3, 3, 3) 

基本ケース
を知っていると仮定すると、

thing = '5985-0' 
d = df.filter(like=thing) 
s = d.apply(tuple, 1).rename(thing) 
cols = d.columns 
df.drop(cols, 1).join(s) 

    333-0  5985-0 
0 123 (1, 1, 1) 
1 123 (2, 2, 2) 
2 123 (3, 3, 3) 

オプション2
filterjoinを使用、使用pd.Series

thing = '5985-0' 
d = df.filter(like=thing) 
s = pd.Series(d.values.tolist(), name=thing) 
cols = d.columns 
df.drop(cols, 1).join(s) 

    333-0  5985-0 
0 123 [1, 1, 1] 
1 123 [2, 2, 2] 
2 123 [3, 3, 3] 

オプション3
filterjoinpd.Series、及びzip

thing = '5985-0' 
d = df.filter(like=thing) 
s = pd.Series(list(zip(*d.values.T)), name=thing) 
cols = d.columns 
print(df.drop(cols, 1).join(s)) 
    333-0  5985-0 
0 123 (1, 1, 1) 
1 123 (2, 2, 2) 
2 123 (3, 3, 3) 

タイミング
大規模データセットの

df = pd.concat([df] * 10000, ignore_index=True 

%%timeit 
thing = '5985-0' 
d = df.filter(like=thing) 
s = d.apply(tuple, 1).rename(thing) 
cols = d.columns 
df.drop(cols, 1).join(s) 
1 loop, best of 3: 350 ms per loop 

%%timeit 
thing = '5985-0' 
cols = ['5985-0.0', '5985-0.1', '5985-0.2'] 
k = len(cols) 
v = df.values 
l = [v[:, df.columns.get_loc(c)].tolist() for c in cols] 
s = pd.Series(list(zip(*l)), name=thing) 
df.drop(cols, 1).join(s) 
100 loops, best of 3: 4.06 ms per loop 

%%timeit 
thing = '5985-0' 
d = df.filter(like=thing) 
s = pd.Series(d.values.tolist(), name=thing) 
cols = d.columns 
df.drop(cols, 1).join(s) 
100 loops, best of 3: 4.56 ms per loop 

%%timeit 
thing = '5985-0' 
d = df.filter(like=thing) 
s = pd.Series(list(zip(*d.values.T)), name=thing) 
cols = d.columns 
df.drop(cols, 1).join(s) 
100 loops, best of 3: 6.89 ms per loop 
+0

すごいです!ありがとう - より包括的なオプションのセットです。私はスピードアップがどこから来るのか全くわかりませんが。私のオリジナルのアプリケーションやタプルと比べると、あなたのソリューションのさまざまなステップは、Cの内部構造をエスケープし、python(list、zip、...)を呼び出すようです。おそらく適用するのが非常に遅い実装ですか? – user48956

+1

@ user48956 'zip'はかなりジッピーです。 'apply'は栄光の' for'ループです。 'd.values.tolist()'は完全にベクトル化されるべきですが、 'zip'はまだまだ高速です。あなたは 'zip'とcomprehensionsから良いパフォーマンスを得ることができます。 – piRSquared

関連する問題