如何使用单个索引更新多索引数据框中的记录

Posted

技术标签:

【中文标题】如何使用单个索引更新多索引数据框中的记录【英文标题】:How to update records in a multiindex dataframe with a single index one 【发布时间】:2019-10-23 18:55:32 【问题描述】:

我需要用单索引数据框更新多索引数据框。新数据框是旧数据框的子集,只有新值,因此不会创建新列或行。仅更新选定的切片,这需要支持一次更新多个列。我希望 pandas 自动进行行索引解析,并且只覆盖提供的行。

这可以在 pandas 0.24.2 中以 API 原生方式完成,无需循环、自定义函数、重置索引或创建多索引吗? (如果您无法切片和更新,那么拥有多索引有什么意义?)我搜索了其他问题,但没有找到适用于此特定用例或提供优雅解决方案的最新答案。

这是一些代码。

df_old = pd.DataFrame(
    [['a', 'x', 0, 0, 0], ['a', 'y', 0, 0, 0], ['a', 'z', 0, 0, 0],
     ['b', 'x', 0, 0, 0], ['b', 'y', 0, 0, 0], ['b', 'z', 0, 0, 0],
    ],
    columns=['i1', 'i2', 'c1', 'c2', 'c3']).set_index(['i1', 'i2'])

df_new = pd.DataFrame([['x', 1, 2], ['y', 3, 4]],
                      columns=['i2', 'c1', 'c2']).set_index('i2')

df_old 
Out[]:
       c1  c2  c3
i1 i2            
a  x    0   0   0
   y    0   0   0
   z    0   0   0
b  x    0   0   0
   y    0   0   0
   z    0   0   0

df_new
Out[]: 
    c1  c2
i2        
x    1   2
y    3   4

理想情况下,我希望下面的单行命令能够正常工作,但它绝对没有任何作用。甚至没有任何警告弹出。我也尝试过合并和加入,但无济于事。

df_old.loc[idx['a'], :].update(df_new)

预期结果如下所示,其中仅更新了选定的“a”切片。

       c1  c2  c3
i1 i2            
a  x    1   2   0
   y    3   4   0
   z    0   0   0
b  x    0   0   0
   y    0   0   0
   z    0   0   0

dataframe summary in one clear picture

谢谢!

【问题讨论】:

在更新时调用 loc 将不起作用,因为 loc 返回一个副本。 @cs95 但是当您设置数值时,它确实会修改原始df(类似于df_old.loc[idx['a', :]]=-1 是的,因为您正在执行分配......语义不同。查看python中__getitem____setitem__的区别。 【参考方案1】:

如果(1)df_new 中的每个索引在df_old 中都有相应的索引,则此解决方案适用于我; (2)i2 索引的顺序在df_olddf_new 中是相同的。第二个约束是必需的,因为左侧切片的元素顺序遵循df_old 而不是df_new.index 中的顺序。我不确定这是错误还是预期行为。

df_old.loc[('a', df_new.index), df_new.columns] = df_new.values

更多关于多索引切片的信息可以在here找到。

【讨论】:

谢谢。我的数据不能保证顺序是一样的。但这可以通过额外的步骤或在同一索引上对两个数据帧进行排序。【参考方案2】:

GZ0 提供的解决方案是迄今为止为使用多索引更新数据框的一部分而实际工作的少数解决方案之一。但是对于我的场景来说它非常缓慢(每 800 个数据点需要 9 秒)。缓慢主要是因为我们正在查找要写入的索引。

我下面的解决方案是 GZ0 解决我的特定场景的解决方案的扩展,它为每只猫运行大约 110 毫秒(大约 800 个数据点)。该解决方案只是通过遵循 subcat 从 df 的原始排序而不是匹配单个索引来覆盖整个系列。可能不是适合所有人的解决方案。

场景: 我只有两个级别的行索引(cat,subcat),并在一个字段(input_field_col)上为所有子猫运行滚动时间序列计算,一个猫一个猫。此时间序列计算的结果会在原始数据框中创建一个新的数据序列列。

ds = df.loc[cat,input_field_col].rolling(winlen).mean()
df.loc[cat,new_col] = ds.values

【讨论】:

以上是关于如何使用单个索引更新多索引数据框中的记录的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Pandas 将多索引系列加入单个索引数据框?

如何更改熊猫数据框中多索引的外层索引?

将多索引数据帧的索引值提取为python中的简单列表

在保持二级索引完整的同时对多索引数据框中的行进行排序

如何从python中的数据框中删除多索引?

如何应用于具有多索引列的数据框中的一组列