2017-09-15 12 views
3

dfサイズが非常に大きいと仮定して、2つのforループを置き換える最速のコードがあるかどうか疑問に思います。私の実際のケースでは、各データフレームは200行と25列です。列のサブセットに基づいてデータフレームをマージして更新する

data_df1 = np.array([['Name','Unit','Attribute','Date'],['a','A',1,2014],['b','B',2,2015],['c','C',3,2016],\ 
       ['d','D',4,2017],['e','E',5,2018]]) 
data_df2 = np.array([['Name','Unit','Date'],['a','F',2019],['b','G',2020],['e','H',2021],\ 
       ['f','I',2022]]) 
df1 = pd.DataFrame(data=data_df1) 
print('df1:') 
print(df1) 
df2 = pd.DataFrame(data=data_df2) 
print('df2:') 
print(df2) 
row_df1 = [1,2,5] 
col_df1 = [1,3] 
row_df2 = [1,2,3] 
col_df2 = [1,2] 
for i in range(0,len(row_df1)): 
    for j in range(0, len(col_df1)): 
     df1.set_value(row_df1[i],col_df1[j], df2.loc[row_df2[i],col_df2[j]]) 
print('df1 after operation:') 
print(df1) 

予想される出力:私が試してみました

df1: 
     0  1   2  3 
0 Name Unit Attribute Date 
1  a  A   1 2014 
2  b  B   2 2015 
3  c  C   3 2016 
4  d  D   4 2017 
5  e  E   5 2018 
df2: 
     0  1  2 
0 Name Unit Date 
1  a  F 2019 
2  b  G 2020 
3  e  H 2021 
4  f  I 2022 
df1 after operation: 
     0  1   2  3 
0 Name Unit Attribute Date 
1  a  F   1 2019 
2  b  G   2 2020 
3  c  C   3 2016 
4  d  D   4 2017 
5  e  H   5 2021 

df1.loc[[1,2,5],[1,3]] = df2.loc[[1,2,3],[1,2]] 
print('df1:') 
print(df1) 
print('df2:') 
print(df2) 

しかし、結果は以下の通りです。予期しないナンがある。

df1: 
     0  1   2  3 
0 Name Unit Attribute Date 
1  a  F   1 NaN 
2  b  G   2 NaN 
3  c  C   3 2016 
4  d  D   4 2017 
5  e NaN   5 NaN 
df2: 
     0  1  2 
0 Name Unit Date 
1  a  F 2019 
2  b  G 2020 
3  e  H 2021 
4  f  I 2022 

ありがとうございます。

答えて

2

いくつかのクリーニング:

def clean_df(df): 
    df.columns = df.iloc[0] 
    df.columns.name = None   
    df = df.iloc[1:].reset_index() 

    return df 

df1 = clean_df(df1) 
df1 
    index Name Unit Attribute Date 
0  1 a A   1 2014 
1  2 b B   2 2015 
2  3 c C   3 2016 
3  4 d D   4 2017 
4  5 e E   5 2018 

df2 = clean_df(df2) 
df2  
    index Name Unit Date 
0  1 a F 2019 
1  2 b G 2020 
2  3 e H 2021 
3  4 f I 2022 

使用mergeon=Nameを指定して、他の列が考慮されないように。

マージと
cols = ['Name', 'Unit_y', 'Attribute', 'Date_y'] 
df1 = df1.merge(df2, how='left', on='Name')[cols]\ 
       .rename(columns=lambda x: x.split('_')[0]).fillna(df1) 

df1 
    Name Unit Attribute Date 
0 a F   1 2019 
1 b G   2 2020 
2 c C   3 2016 
3 d D   4 2017 
4 e H   5 2021 
+0

@John私はあなたの出力を得る方法を示しました。 –

+0

@ジョンあなたが間違った答えを得ようとしていると主張するなら、それはあなたのデータであり、私の問題ではないからです。私はあなたがこれをやっている2回目であり、質問に答える努力と、それに付随する情報の乱れを認めないことに注意してください。 –

+0

@COLDSPEED私は本当にあなたの助けに感謝します。 df1.T.reset_index()を使用した後の私のノートブックに表示される結果は、Tが最初の列のインデックス0,1,2,3を持たないこと、つまり 'Name'、 'Unit' .etcはdf1.columns.valuesとして返された結果です。 – John

1

別の方法と転置データフレームに基づいて重複を削除し、ffillすなわち

new_df = df1.merge(df2,on=[0],how='outer').T.set_index(0).sort_index() 
     .ffill().reset_index().drop_duplicates(0,keep='last').T.dropna() 
 
      0  2  3  5 
0 Attribute Date Name Unit 
1   1 2019  a  F 
2   2 2020  b  G 
3   3 2016  c  C 
4   4 2017  d  D 
5   5 2021  e  H 

説明

df1.merge(df2,on=[0],how='outer').T.set_index(0).sort_index() 

転置データフレームは、我々が適用できるようなデータフレームを与えますナノ値を埋めるために埋めてください

 
      1  2  3  4  5  6 
0            
Attribute  1  2  3  4  5 NaN 
Date  2014 2015 2016 2017 2018 NaN 
Date  2019 2020 NaN NaN 2021 2022 
Name   a  b  c  d  e  f 
Unit   A  B  C  D  E NaN 
Unit   F  G NaN NaN  H  I 
.ffill().reset_index().drop_duplicates(0,keep='last') 

これがNaNを充填するには、前の行のデータサブセット0のドロップ重複とreset_indexと値と完全に充填された行を維持する最後に保ちます。

 
     0  1  2  3  4  5  6 
0 Attribute  1  2  3  4  5 NaN 
2  Date 2019 2020 2016 2017 2021 2022 
3  Name  a  b  c  d  e  f 
5  Unit  F  G  C  D  H  I 
.T.dropna() 

これは、データフレームは、所望の出力が得られるNaN値を持つ行を削除回転します。

0

私はまた、以下のコードが私が望むものを実行し、2つのforループよりもはるかに高速であることを理解しました。

df1.loc[[1,2,5],[1,3]] = df2.loc[[1,2,3],[1,2]].values