2017-05-07 15 views
3

複数の列に条件付きデータフレームをマージdf1):パンダ - 私は2つのデータフレームを持っていると私は((他の)列</p> <p>まずデータフレームを1から列のいずれかを実行し、複数の値に基づいて、第2に新しい列を作成したい

df1 = pd.DataFrame({'cond': np.repeat([1,2], 5), 
        'point': np.tile(np.arange(1,6), 2), 
        'value1': np.random.rand(10), 
        'unused1': np.random.rand(10)}) 

    cond point unused1 value1 
0  1  1 0.923699 0.103046 
1  1  2 0.046528 0.188408 
2  1  3 0.677052 0.481349 
3  1  4 0.464000 0.807454 
4  1  5 0.180575 0.962032 
5  2  1 0.941624 0.437961 
6  2  2 0.489738 0.026166 
7  2  3 0.739453 0.109630 
8  2  4 0.338997 0.415101 
9  2  5 0.310235 0.660748 

及び第二(df2):

df2 = pd.DataFrame({'cond': np.repeat([1,2], 10), 
        'point': np.tile(np.arange(1,6), 4), 
        'value2': np.random.rand(20)}) 

    cond point value2 
0  1  1 0.990252 
1  1  2 0.534813 
2  1  3 0.407325 
3  1  4 0.969288 
4  1  5 0.085832 
5  1  1 0.922026 
6  1  2 0.567615 
7  1  3 0.174402 
8  1  4 0.469556 
9  1  5 0.511182 
10  2  1 0.219902 
11  2  2 0.761498 
12  2  3 0.406981 
13  2  4 0.551322 
14  2  5 0.727761 
15  2  1 0.075048 
16  2  2 0.159903 
17  2  3 0.726013 
18  2  4 0.848213 
19  2  5 0.284404 

df1['value1']はEACの値が含まれhの組合せである。condpoint

私はdf1['value1']からの値を含むdf2で新しい列(new_column)を作成したいのですが、値がcondpointは2つのデータフレーム間で一致しているものでなければなりません。

だから私の所望の出力は次のようになります。この例では

cond point value2 new_column 
0  1  1 0.990252 0.103046 
1  1  2 0.534813 0.188408 
2  1  3 0.407325 0.481349 
3  1  4 0.969288 0.807454 
4  1  5 0.085832 0.962032 
5  1  1 0.922026 0.103046 
6  1  2 0.567615 0.188408 
7  1  3 0.174402 0.481349 
8  1  4 0.469556 0.807454 
9  1  5 0.511182 0.962032 
10  2  1 0.219902 0.437961 
11  2  2 0.761498 0.026166 
12  2  3 0.406981 0.109630 
13  2  4 0.551322 0.415101 
14  2  5 0.727761 0.660748 
15  2  1 0.075048 0.437961 
16  2  2 0.159903 0.026166 
17  2  3 0.726013 0.109630 
18  2  4 0.848213 0.415101 
19  2  5 0.284404 0.660748 

私はちょうどタイル/リピートを使用することができますが、実際df1['value1']に他のデータフレームにそうきちんと収まりません。 :だから私はちょうど私がdf1から任意の未使用の列の上に持って帰りたいと思ういけない)私はそれらをマージしようとしましたが、1)の数字が一致し、2ように見えるいけないcondpoint

の一致に基づいて、それを実行する必要があります

df1.merge(df2, left_on=['cond', 'point'], right_on=['cond', 'point'])

いただきました2つのデータフレームを反復処理することなく、この新しい列を追加するための正しい方法?

答えて

2

オプション1
純粋pandasと優雅さと速さのために、私たちはこれは以下の見て他のすべてのオプション、同じ出力を生成しますlookup
を使用することができます。

概念は、ルックアップデータを2次元配列として表現し、インデックスを使用して値を検索することです。

d1 = df1.set_index(['cond', 'point']).value1.unstack() 
df2.assign(new_column=d1.lookup(df2.cond, df2.point)) 

オプション2
我々は値が、彼らはdf1にいるのと同じ方法で提示されている場合は、パフォーマンスを向上させるためにnumpyと同じことを行うことができます。これは非常に速いです!

a = df1.value1.values.reshape(2, -1) 
df2.assign(new_column=a[df2.cond.values - 1, df2.point.values - 1]) 

オプション3
標準的な答えはmerge with the left parameter
を使用することです。しかし、我々は、出力

d1 = df1[['cond', 'point', 'value1']].rename(columns={'value1': 'new_column'}) 
df2.merge(d1, 'left') 

に爪にdf1を少し準備をする必要がありますオプション4
私はこれが楽しいと思った。
大きなデータには適していませんが、大きなデータには適していません。以下のタイミングを参照してください。

c1 = df1.cond.values.tolist() 
p1 = df1.point.values.tolist() 
v1 = df1.value1.values.tolist() 
m = {(c, p): v for c, p, v in zip(c1, p1, v1)} 

c2 = df2.cond.values.tolist() 
p2 = df2.point.values.tolist() 
i2 = df2.index.values.tolist() 
s2 = pd.Series({i: (c, p) for i, c, p in zip(i2, c2, p2)}) 

df2.assign(new_column=s2.map(m)) 

OUTPUT

cond point value2 new_column 
0  1  1 0.990252 0.103046 
1  1  2 0.534813 0.188408 
2  1  3 0.407325 0.481349 
3  1  4 0.969288 0.807454 
4  1  5 0.085832 0.962032 
5  1  1 0.922026 0.103046 
6  1  2 0.567615 0.188408 
7  1  3 0.174402 0.481349 
8  1  4 0.469556 0.807454 
9  1  5 0.511182 0.962032 
10  2  1 0.219902 0.437961 
11  2  2 0.761498 0.026166 
12  2  3 0.406981 0.109630 
13  2  4 0.551322 0.415101 
14  2  5 0.727761 0.660748 
15  2  1 0.075048 0.437961 
16  2  2 0.159903 0.026166 
17  2  3 0.726013 0.109630 
18  2  4 0.848213 0.415101 
19  2  5 0.284404 0.660748 

タイミング
小さなデータ

%%timeit 
a = df1.value1.values.reshape(2, -1) 
df2.assign(new_column=a[df2.cond.values - 1, df2.point.values - 1]) 
1000 loops, best of 3: 304 µs per loop 

%%timeit 
d1 = df1.set_index(['cond', 'point']).value1.unstack() 
df2.assign(new_column=d1.lookup(df2.cond, df2.point)) 
100 loops, best of 3: 1.8 ms per loop 

%%timeit 
c1 = df1.cond.values.tolist() 
p1 = df1.point.values.tolist() 
v1 = df1.value1.values.tolist() 
m = {(c, p): v for c, p, v in zip(c1, p1, v1)} 
​ 
c2 = df2.cond.values.tolist() 
p2 = df2.point.values.tolist() 
i2 = df2.index.values.tolist() 
s2 = pd.Series({i: (c, p) for i, c, p in zip(i2, c2, p2)}) 
​ 
df2.assign(new_column=s2.map(m)) 
1000 loops, best of 3: 719 µs per loop 

%%timeit 
d1 = df1[['cond', 'point', 'value1']].rename(columns={'value1': 'new_column'}) 
df2.merge(d1, 'left') 
100 loops, best of 3: 2.04 ms per loop 

%%timeit 
df = pd.merge(df2, df1.drop('unused1', axis=1), 'left') 
df.rename(columns={'value1': 'new_column'}) 
100 loops, best of 3: 2.01 ms per loop 

%%timeit 
df = df2.join(df1.drop('unused1', axis=1).set_index(['cond', 'point']), on=['cond', 'point']) 
df.rename(columns={'value1': 'new_column'}) 
100 loops, best of 3: 2.15 ms per loop 

大規模データ

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

%%timeit 
a = df1.value1.values.reshape(2, -1) 
df2.assign(new_column=a[df2.cond.values - 1, df2.point.values - 1]) 
1000 loops, best of 3: 1.93 ms per loop 

%%timeit 
d1 = df1.set_index(['cond', 'point']).value1.unstack() 
df2.assign(new_column=d1.lookup(df2.cond, df2.point)) 
100 loops, best of 3: 5.58 ms per loop 

%%timeit 
c1 = df1.cond.values.tolist() 
p1 = df1.point.values.tolist() 
v1 = df1.value1.values.tolist() 
m = {(c, p): v for c, p, v in zip(c1, p1, v1)} 
​ 
c2 = df2.cond.values.tolist() 
p2 = df2.point.values.tolist() 
i2 = df2.index.values.tolist() 
s2 = pd.Series({i: (c, p) for i, c, p in zip(i2, c2, p2)}) 
​ 
df2.assign(new_column=s2.map(m)) 
10 loops, best of 3: 135 ms per loop 

%%timeit 
d1 = df1[['cond', 'point', 'value1']].rename(columns={'value1': 'new_column'}) 
df2.merge(d1, 'left') 
100 loops, best of 3: 13.4 ms per loop 

%%timeit 
df = pd.merge(df2, df1.drop('unused1', axis=1), 'left') 
df.rename(columns={'value1': 'new_column'}) 
10 loops, best of 3: 19.8 ms per loop 

%%timeit 
df = df2.join(df1.drop('unused1', axis=1).set_index(['cond', 'point']), on=['cond', 'point']) 
df.rename(columns={'value1': 'new_column'}) 
100 loops, best of 3: 18.2 ms per loop 
あなたは left joinmergeを使用することができます
+0

おかげで@jezrael。あなたも。 – piRSquared

2

dropためunused1列を削除し、最後のrenameコラム:

お知らせ

:パラメータonは両方DataFramesであれば省略することができます結合の列は同じです。同じ列名の場合は、on=['cond', 'point']を追加します。

df = pd.merge(df2, df1.drop('unused1', axis=1), 'left') 
df = df.rename(columns={'value1': 'new_column'}) 
print (df) 
    cond point value2 new_column 
0  1  1 0.990252 0.103046 
1  1  2 0.534813 0.188408 
2  1  3 0.407325 0.481349 
3  1  4 0.969288 0.807454 
4  1  5 0.085832 0.962032 
5  1  1 0.922026 0.103046 
6  1  2 0.567615 0.188408 
7  1  3 0.174402 0.481349 
8  1  4 0.469556 0.807454 
9  1  5 0.511182 0.962032 
10  2  1 0.219902 0.437961 
11  2  2 0.761498 0.026166 
12  2  3 0.406981 0.109630 
13  2  4 0.551322 0.415101 
14  2  5 0.727761 0.660748 
15  2  1 0.075048 0.437961 
16  2  2 0.159903 0.026166 
17  2  3 0.726013 0.109630 
18  2  4 0.848213 0.415101 
19  2  5 0.284404 0.660748 

set_index + dropjoin(デフォルトleft join)と別の解決策:

df = df2.join(df1.drop('unused1', axis=1).set_index(['cond', 'point']), on=['cond', 'point']) 
df = df.rename(columns={'value1': 'new_column'}) 
print (df) 
    cond point value2 new_column 
0  1  1 0.990252 0.103046 
1  1  2 0.534813 0.188408 
2  1  3 0.407325 0.481349 
3  1  4 0.969288 0.807454 
4  1  5 0.085832 0.962032 
5  1  1 0.922026 0.103046 
6  1  2 0.567615 0.188408 
7  1  3 0.174402 0.481349 
8  1  4 0.469556 0.807454 
9  1  5 0.511182 0.962032 
10  2  1 0.219902 0.437961 
11  2  2 0.761498 0.026166 
12  2  3 0.406981 0.109630 
13  2  4 0.551322 0.415101 
14  2  5 0.727761 0.660748 
15  2  1 0.075048 0.437961 
16  2  2 0.159903 0.026166 
17  2  3 0.726013 0.109630 
18  2  4 0.848213 0.415101 
19  2  5 0.284404 0.660748 
関連する問題