Python Pandas - 通过将标签与列匹配,将值从一个数据框添加到另一个数据框

时间:2018-04-09 16:32:33

标签: python pandas dataframe

我知道这个问题有一个简单,优雅的解决方案,但我很难找到它。我试图做的就是根据日期和PN,将第三列添加到df2,并使用df2中的相应值。 df2中的值可能与df1不匹配,反之亦然(填充没有匹配的NaN)。

DF1:

       2017-11-01  2017-11-02  2017-11-03
PN                                                                              
90020       105.0       105.0       105.0
90022       100.0       100.0       100.0 
90061        -3.0        -3.0        -3.0 
90065        30.0        30.0        30.0
90099         2.0         2.0         2.0

DF2:

     PN       Date
4   90020 2017-11-01
9   90020 2017-11-02
12  90061 2017-11-01
13  90065 2017-11-02
17  94008 2017-11-03

期望的结果:

     PN       Date      Value
4   90020 2017-11-01    105.0
9   90020 2017-11-02    105.0
12  90061 2017-11-01    -3.0
13  90065 2017-11-02    30.0
17  94008 2017-11-03    NaN

5 个答案:

答案 0 :(得分:4)

如上所述,您可以将pd.meltpd.merge结合使用。

只需记得reset_index将索引提升为列,然后对齐列名称。

df1 = pd.melt(df.reset_index(), id_vars=df.index.name)\
        .rename(columns={'variable': 'Date'})

res = pd.merge(df2, df1, how='left')

#       PN        Date  value
# 0  90020  2017-11-01  105.0
# 1  90020  2017-11-02  105.0
# 2  90061  2017-11-01   -3.0
# 3  90065  2017-11-02   30.0
# 4  94008  2017-11-03    NaN

维持df2索引:

res = df2.reset_index()\
         .merge(df1, how='left')\
         .set_index('index')

#           PN        Date  value
# index                          
# 4      90020  2017-11-01  105.0
# 9      90020  2017-11-02  105.0
# 12     90061  2017-11-01   -3.0
# 13     90065  2017-11-02   30.0
# 17     94008  2017-11-03    NaN

答案 1 :(得分:3)

另一个解决方案是使用stack()创建df1的地图,然后将其应用于列的zip。

m = df1.stack()
df2['value'] = pd.Series(list(zip(df2.PN, df2.Date))).map(m).values

#          PN        Date  value
#index                          
#4      90020  2017-11-01  105.0
#9      90020  2017-11-02  105.0
#12     90061  2017-11-01   -3.0
#13     90065  2017-11-02   30.0
#17     94008  2017-11-03    NaN

时间比较

  

jpp的融合和合并:100个循环,最佳3:每循环4.41 ms

     

avbr的堆栈和映射:100个循环,最佳3:2.97毫秒/循环

     

ScottB的堆栈,重新索引:100个循环,最佳3:3.68毫秒/循环

     

ThisGuy的函数,listcomprehension:100个循环,最佳3:5.79 ms每个循环

完整示例:

import pandas as pd

data1 = '''\
PN         2017-11-01  2017-11-02  2017-11-03
90020       105.0       105.0       105.0
90022       100.0       100.0       100.0
90061        -3.0        -3.0        -3.0 
90065        30.0        30.0        30.0
90099         2.0         2.0         2.0'''

data2 = '''\
index     PN       Date
4   90020 2017-11-01
9   90020 2017-11-02
12  90061 2017-11-01
13  90065 2017-11-02
17  94008 2017-11-03
'''

df1 = pd.read_csv(pd.compat.StringIO(data1), sep='\s+').set_index('PN')
df2 = pd.read_csv(pd.compat.StringIO(data2), sep='\s+').set_index('index')

m = df1.stack()
df2['value'] = pd.Series(list(zip(df2.PN, df2.Date))).map(m).values

答案 2 :(得分:2)

你也可以这样做。

(df1.stack()
   .rename_axis(['PN','Date'])
   .reindex([df2.PN,df2['Date']])
   .reset_index(name='Value')
   .set_axis(df2.index, axis=0, inplace=False))

@AntonVBR建议使用:

(df1.stack()
   .rename_axis(['PN','Date'])
   .reindex([df2.PN,df2['Date']])
   .reset_index(name='Value')
   .set_index(df2.index))

输出:

       PN        Date  Value
4   90020  2017-11-01  105.0
9   90020  2017-11-02  105.0
12  90061  2017-11-01   -3.0
13  90065  2017-11-02   30.0
17  94008  2017-11-03    NaN

答案 3 :(得分:2)

我们走了。上面没有列出这个解决方案(可能是因为它几乎不可读,并且涉及在python中循环,这会降低性能):

def cnvt (i):
    try:
        return i[0]
    except(IndexError):
        return float('nan')

df3 = df2.assign(Value=list(map(cnvt,[
           df1[i][df1["PN"]==j].values 
           for i in list(df1.columns.values[1:]) 
           for j in df2["PN"]][0:len(df2["PN"]-1)]
                 )))

创建df3

          Date     PN  Value
4   2017-11-01  90020  105.0
9   2017-11-02  90020  105.0
12  2017-11-01  90061   -3.0
13  2017-11-02  90065   30.0
17  2017-11-03  94008    NaN

答案 4 :(得分:0)

我正在考虑lookup,但它失败了

  

KeyError:'未找到一个或多个行标签'

#df1.lookup(df2.PN,df2.Date,na_action='ignore')

result = []
for x,y in zip(df2.PN, df2.Date):
    try:
        result.append(df1.get_value(x, y))
    except:
        result.append(np.nan)



df2['V']=result