Python 有效地获得指数的并集
我有两个熊猫数据帧Python 有效地获得指数的并集,python,performance,pandas,Python,Performance,Pandas,我有两个熊猫数据帧df1和df2,我想要它们的“合并索引” 这里我指的是当我执行例如df1.add(df2,fill\u value=0)时获得的索引。这种计算(这里,add)是在单独的脚本中执行的,我不想在这些脚本中计算“合并索引”,但我也希望在我只对“合并索引”感兴趣时避免进行这些计算 有没有更“直接”(希望更有效)的方法 我的目标实际上是将“标记”与索引元素相关联。我有几对数据帧。每对对应一个“标签”,可能有重叠的索引。不同的对对应不同的标签,它们应该没有重叠的索引 基本上,我正在寻找一个
df1
和df2
,我想要它们的“合并索引”
这里我指的是当我执行例如df1.add(df2,fill\u value=0)时获得的索引。这种计算(这里,add
)是在单独的脚本中执行的,我不想在这些脚本中计算“合并索引”,但我也希望在我只对“合并索引”感兴趣时避免进行这些计算
有没有更“直接”(希望更有效)的方法
我的目标实际上是将“标记”与索引元素相关联。我有几对数据帧。每对对应一个“标签”,可能有重叠的索引。不同的对对应不同的标签,它们应该没有重叠的索引
基本上,我正在寻找一个有效的associate_tag
函数实现,其工作如下:
dfA_1
:
idA_1 2 0
idA_2 1 0
idA_3 0 2
idB_1 2 2 1
idB_2 3 0 0
idB_3 3 1 3
dfA_2
:
idA_1 3 2 1
idA_3 2 6 2
idA_4 4 0 2
idB_1 0
idB_2 3
idB_4 2
merge_A=associate_标记((dfA_1,dfA_2),“A”)
:
dfB_1
:
idA_1 2 0
idA_2 1 0
idA_3 0 2
idB_1 2 2 1
idB_2 3 0 0
idB_3 3 1 3
dfB_2
:
idA_1 3 2 1
idA_3 2 6 2
idA_4 4 0 2
idB_1 0
idB_2 3
idB_4 2
merge_B=associate_标记((dfB_1,dfB_2),“B”)
:
total\u merge=pd.concat((merge\u A,merge\u B))
:
我知道与给定数据帧对的索引元素关联的标签,理想情况下,associate_标签
函数将完全忽略数据帧中的数字
下面是一个不理想的实现:
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\u merge
轻松地向包含混合索引元素的数据帧添加一个“tag”列。例如,我可以:
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
有没有更好的方法来执行这种操作?根据您的意见,这里有一个改进的解决方案:
两部分:
结合您的数据帧,根据您的列名,您可以在确保列名对齐后,对整个数据帧列表进行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
然后
要用零填充这些NAN,请执行以下操作:
final.fillna(0, inplace=True)
第2部分,标签:
一旦您知道创建标记与定义索引映射一样简单,您就可以编写简单的函数、硬编码dict或使用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
我最终发现pandasIndex
对象有一个\uuuuuuuuuuuuuuuuuuuuuuuuuuu
实现
希望以下版本的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)
不知何故,我希望pandas有一种内部有效的方法来实现这一点(我想当我添加数据帧时它会这样做),这样我就不必“手动”构建重复数据消除索引。您可以使用已知标记的事实来简化解决方案的最后一步:final[“tag”]=“A”
。此外,在我的真实案例中,无论如何都不能简单地从行名称推断标记。您知道使用concat
是否比使用add
更有效吗?就像我在“非理想实现”中所做的那样?是的,我只是将标记映射到第三个字符,因为这也会在示例数据中给出正确的B标记,但您可以创建一个带有离散映射或函数的dict,具体取决于实际ID的外观。您也可以将dict传递给map。我不确定concat在所有用例中是否都更有效,但它使用内置函数实现起来更简单。你没有提到速度是一个限制,但我敢打赌它至少同样好,调试起来也简单得多。如果不清楚的话,只要每个数据帧中的列名对齐,concat将处理一个数据帧列表,并按照预期的方式运行。所以不需要循环,只需要pd.concat(dfs)。您可以消除对itertools操作符和functools的需要,从而很好地清理它。