我知道这个问题有一个简单,优雅的解决方案,但我很难找到它。我试图做的就是根据日期和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
答案 0 :(得分:4)
如上所述,您可以将pd.melt
与pd.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