微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何基于一级掩码填充多索引数据框

如何解决如何基于一级掩码填充多索引数据框

我有一个多索引数据帧。

import pandas as pd
from itertools import product
arrays = [['bar','baz','foo'],range(4)]
tuples = list(product(*arrays))
index = pd.MultiIndex.from_tuples(tuples,names=['first','second'])
multi_ind=pd.DataFrame(np.random.randn(6,len(tuples)),index=range(6),columns=index)

有些值是nans:

multi_ind.loc[3,('bar',2)]=np.nan
multi_ind.loc[3,3)]=np.nan
multi_ind.loc[4,1)]=np.nan

enter image description here

对于'bar',我想填写所有nans的最后期望,如以下所述:

Forward fill all except last value in python pandas dataframe

mask=multi_ind['bar']
last_valid_column_per_row = mask.apply(pd.Series.last_valid_index,axis=1)
mask=mask.apply(lambda series:series[:int(last_valid_column_per_row.loc[series.name])].ffill(),axis=1)

然后,我想使用与bar(从{{到最后一个有效索引)相同的逻辑,也ffill()也使用其他第一层(例如bazfoo) 1}}),并且我想同时为df['bar']

中仍为nan的任何值设置一个nan

如何有效地实现这一目标?

现在我正在执行以下操作,但是速度很慢...

bar

解决方法

基于 last_valid_index 的代码(在指定的帖子中)实际上 沿给定轴填充 NaN

  • 没有初始 NaN 单元格(填充没有先前的值 作为来源)
  • 没有跟踪 NaN 细胞(无论其数量如何), 由于 last_valid_index 而终止了操作 在 NaN s的尾随连续序列之前,

但是如果您对此安排感到满意,那就顺其自然吧。

我通过以下更简洁的方式创建了测试DataFrame:

arrays = [['bar','baz','foo'],range(4)]
cols = pd.MultiIndex.from_product(arrays,names=['first','second'])
np.random.seed(2)
arr = np.arange(1,6 * 12 + 1,dtype=float).reshape(6,-1)
# Where to put NaN (x / y)
ind = (np.array([0,1,2,3,4,5,5]),np.array([1,6,10,11]))
arr[ind] = np.nan
multi_ind = pd.DataFrame(arr,columns=cols)

包含以下内容:

first    bar                     baz                     foo                  
second     0     1     2     3     0     1     2     3     0     1     2     3
0        1.0   NaN   NaN   4.0   5.0   6.0   7.0   8.0   9.0  10.0  11.0  12.0
1       13.0  14.0  15.0  16.0  17.0  18.0   NaN  20.0  21.0  22.0  23.0  24.0
2       25.0   NaN  27.0   NaN  29.0   NaN  31.0  32.0  33.0  34.0  35.0  36.0
3       37.0  38.0  39.0  40.0  41.0  42.0  43.0  44.0  45.0  46.0   NaN  48.0
4       49.0  50.0   NaN   NaN  53.0  54.0  55.0  56.0  57.0  58.0  59.0  60.0
5       61.0  62.0  63.0  64.0  65.0  66.0  67.0  68.0  69.0  70.0   NaN   NaN

要获得结果,请运行:

result = multi_ind.stack(level=0).apply(
    lambda row: row[: row.last_valid_index() + 1].ffill(),axis=1)\
    .unstack(level=1).swaplevel(axis=1).reindex(columns=multi_ind.columns)

请注意,您不需要 last_valid_column_per_row 。 传递 axis = 1 即可对行进行操作,而不是 列(如指示的帖子中所示)。

结果是:

first    bar                     baz                     foo                  
second     0     1     2     3     0     1     2     3     0     1     2     3
0        1.0   1.0   1.0   4.0   5.0   6.0   7.0   8.0   9.0  10.0  11.0  12.0
1       13.0  14.0  15.0  16.0  17.0  18.0  18.0  20.0  21.0  22.0  23.0  24.0
2       25.0  25.0  27.0   NaN  29.0  29.0  31.0  32.0  33.0  34.0  35.0  36.0
3       37.0  38.0  39.0  40.0  41.0  42.0  43.0  44.0  45.0  46.0  46.0  48.0
4       49.0  50.0   NaN   NaN  53.0  54.0  55.0  56.0  57.0  58.0  59.0  60.0
5       61.0  62.0  63.0  64.0  65.0  66.0  67.0  68.0  69.0  70.0   NaN   NaN

详细信息:

  • stack(level=0)-将 bar baz foo “片段”放入 在连续的行中。
  • apply(….ffill(),axis=1)-每行填充,无尾随 NaN 的序列(如果有)。请注意,我添加了 +1 在结果中包含最后一个非 NaN 值。否则最后 列将被删除。
  • unstack(level=1)-恢复先前的(“宽”)排列, 但不幸的是,列MultiIndex级别的顺序是相反的。
  • swaplevel(axis=1)-恢复列级别的原始顺序, 但不幸的是,列名的顺序是错误的。
  • reindex(…)-恢复原始列顺序。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。