有效地获得熊猫指数的联合

时间:2017-06-26 14:18:48

标签: python performance pandas

我有两个pandas数据帧df1df2,我希望他们的"合并索引"。

我的意思是当我做例如df1.add(df2, fill_value=0).index时获得的索引(基本上是行名称的联合)。这种计算(这里,add)是在单独的脚本中执行的,我不想计算"合并索引"在这些脚本中,但我还想避免在我对#34;合并索引"感兴趣时进行这些计算。

还有更多"直接" (并希望有效率)这样做的方式?

我的目标实际上是关联"标签"索引元素。我有几对数据帧。每对对应一个标签"并且可能有重叠的指数。不同的对应对应不同的标签,并且它们应该没有重叠的索引。

基本上,我正在寻找一种有效的associate_tag函数实现,该函数的工作原理如下:

dfA_1

idA_1    2    0
idA_2    1    0
idA_3    0    2

dfA_2

idA_1    3    2    1
idA_3    2    6    2
idA_4    4    0    2

merge_A = associate_tag((dfA_1, dfA_2), "A")

idA_1    A
idA_2    A
idA_3    A
idA_4    A

dfB_1

idB_1    2    2    1
idB_2    3    0    0
idB_3    3    1    3

dfB_2

idB_1    0
idB_2    3
idB_4    2

merge_B = associate_tag((dfB_1, dfB_2), "B")

idB_1    B
idB_2    B
idB_3    B
idB_4    B

total_merge = pd.concat((merge_A, merge_B))

idA_1    A
idA_2    A
idA_3    A
idA_4    A
idB_1    B
idB_2    B
idB_3    B
idB_4    B

我知道要与给定数据帧对的索引元素关联的标记,associate_tag函数理想地完全忽略数据帧中的数字。

这是一个非理想的实现:

from functools import reduce
from itertools import repeat

def add_dataframes(df1, df2):
    return df1.add(df2, fill_value=0)

def sum_dataframes(dfs):
    return reduce(add_dataframes, dfs)

def associate_tag(dfs, tag):
    return pd.concat((sum_dataframes(dfs).index, repeat(tag)), axis=1)

def associate_tag(dfs, tag):   
    s = sum_dataframes(dfs)
    return pd.DataFrame(list(zip(s.index, repeat(tag)))).set_index(0)

我打算使用此total_merge轻松添加"标记"列到包含索引元素混合的数据帧。例如,我可以:

df

idA_2    5    4    1
idB_1    1    0    0
idB_4    2    1    2
idA_4    2    3    2

然后我会使用pd.concat((df, total_merge), join="inner", axis=1)添加带标签的额外列:

idA_2    5    4    1    A
idB_1    1    0    0    B
idB_4    2    1    2    B
idA_4    2    3    2    A

有没有更好的方法来进行这种操作?

2 个答案:

答案 0 :(得分:2)

我终于发现pandas Index对象实现了__or__

希望以下版本的associate_tag避免多余的操作:

from operator import or_ as union
from itertools import repeat
from functools import reduce

def associate_tag(dfs, tag):   
    idx = reduce(union, (df.index for df in dfs))
    return pd.DataFrame(list(zip(idx, repeat(tag)))).set_index(0)

答案 1 :(得分:0)

根据您的评论,这是一个经过修改的解决方案:

两部分: 结合您的数据框架,根据您的列名称,一旦确定列名称排列,您就可以pd.concat整个数据框列表。因此,如果: dfA_1是:

       col1  col2
index            
idA_1     2     0
idA_2     1     0
idA_3     0     2

和 dfA_2是:

       col1  col2  col3
index                  
idA_1     3     2     1
idA_3     2     6     2
idA_4     4     0     2

然后

final = pd.concat([dfA_1,dfA_2])

final
       col1  col2  col3
index                  
idA_1     2     0   NaN
idA_2     1     0   NaN
idA_3     0     2   NaN
idA_1     3     2   1.0
idA_3     2     6   2.0
idA_4     4     0   2.0

用零填充这些NaN:

final.fillna(0, inplace=True)

第2部分,标签: 一旦你创建了标签就像为索引定义一个地图一样简单,你可以写一个简单的函数,硬编码一个字典,或者使用一个lambda:

final['tag'] = final.index.map(lambda x: x[2])

final
       col1  col2  col3 tag
index                      
idA_1     2     0   0.0   A
idA_2     1     0   0.0   A
idA_3     0     2   0.0   A
idA_1     3     2   1.0   A
idA_3     2     6   2.0   A
idA_4     4     0   2.0   A