根据pandas中的外键减去多个列

时间:2016-11-15 14:49:52

标签: python pandas

我试图计算一个物体与它的基准之间的差异。我有一个数据集,其中包含所有对象的日常记录及其相应的值,如下所示:

obj_df
date         id   value_a value_b value_c value_d  benchmark_id
01/21/2015  abc        10      41      19      22           efg
01/22/2015  abc        15      43      11      21           efg
01/21/2015  xyz        16      45      13      26           tuv
01/22/2015  xyz        13      48      12      22           tuv
01/21/2015  tru        10      39      15      21           efg
01/21/2015  tru        11      37      13      20           efg

我也有关于基准的数据。值列在数据框之间共享。基准集中的id对应于原始对象数据帧中的基准ID。

bm_df
date         id   value_a value_b value_c value_d
01/21/2015  efg        12      40      12      20
01/22/2015  efg        15      41      14      21
01/21/2015  tuv        14      42      11      19
01/22/2015  tuv        13      43      19      17

我试图找到一种简单的方法来返回一个数据框,它给出了对象值和相应基准值之间的差异,以获得看起来像这样的数据框。

diff_df
date         id    diff_a  diff_b  diff_c  diff_d benchmark_id
01/21/2015  abc        -2       1       7       2          efg
01/22/2015  abc         0       2      -3       0          efg
01/21/2015  xyz         2       3       2       7          tuv
01/22/2015  xyz         0       5      -7       5          tuv
01/21/2015  tru        -4      -3       4       2          efg
01/21/2015  tru        -2      -6      -6       3          efg

有几点需要注意:
  - 有多个对象而不是基准,因此索引的大小不一样   - 每个对象都有一个基准   - 我并不特别关心原始价值观。差别就是这样   - 某些基准对应于多个对象。例如,两个' abc'和' tru'使用' efg'作为基准。

4 个答案:

答案 0 :(得分:4)

我认为您可以使用sub,然后将idbenchmark_id列添加到concat列,将reindex列添加到https://jsfiddle.net/63wm1r01/23/列的列中1}}:

obj_df
print (obj_df) 
                value_a  value_b  value_c  value_d benchmark_id
date       id                                                  
01/21/2015 abc       10       41       19       22          efg
01/22/2015 abc       15       43       11       21          efg
01/21/2015 xyz       16       45       13       26          tuv
01/22/2015 xyz       13       48       12       22          tuv

print (bm_df)
                value_a  value_b  value_c  value_d
date       id                                     
01/21/2015 efg       12       40       12       20
01/22/2015 efg       15       41       14       21
01/21/2015 tuv       14       42       11       19
01/22/2015 tuv       13       43       19       17

答案 1 :(得分:3)

odf = obj_df.set_index(['date', 'benchmark_id'])
bdf = bm_df.set_index(['date', 'id'])

odf.update(odf.drop('id', 1).sub(bdf))
odf.reset_index().reindex_axis(obj_df.columns, 1)

exclude_end?

答案 2 :(得分:1)

<强> 步骤:

执行合并:

df = obj_df.merge(bm_df, left_on=['benchmark_id', 'date'], right_on=['id', 'date'])    \
           .drop(['id_y'], 1).set_index(['date'])

通过输入起始和结束列名来查找列索引位置的辅助函数:

def col_locate(df, start, end):
    start_loc = df.columns.get_loc(start)
    end_loc = df.columns.get_loc(end)
    return list(range(start_loc, end_loc+1))

fir, sec = col_locate(df,'value_a_x','value_d_x'), col_locate(df,'value_a_y','value_d_y')

objectDFbenchmarkDF

中减去值
df_diff = pd.DataFrame(df.iloc[:, fir].values - df.iloc[:, sec].values, 
                       columns=list('abcd'), index=df.index).add_prefix('diff_')

最后,以列方式连接它们:

pd.concat([df[['id_x', 'benchmark_id']], df_diff], axis=1)

enter image description here

注意: 更新用于获得结果的DF

答案 3 :(得分:0)

使用合并:

select.change();