Pandas:具有多索引的 fillna() 方法 - NaN 填充了错误的列

Posted

技术标签:

【中文标题】Pandas:具有多索引的 fillna() 方法 - NaN 填充了错误的列【英文标题】:Pandas: fillna() method with multiindex - NaNs are filled with wrong columns 【发布时间】:2014-11-18 02:24:44 【问题描述】:

这是一个重现我的问题的工作示例。首先会生成一些随机数据以及我们将用来填充 nans 的数据:

#Generate some random data and data that will be used to fill the nans
data = np.random.random((100,6))
fill_data = np.vstack((np.ones(200), np.ones(200)*2, np.ones(200)*3,np.ones(200), np.ones(200)*2, np.ones(200)*3)).T

#Generate indices of nans that we will put in
nan_rows = np.random.randint(0,100,50)
nan_cols = np.random.randint(0,6,50)
nan_idx = np.vstack((nan_rows,nan_cols)).T

#Put in nan values
for r,c in nan_idx:
    data[r,c] = np.nan

#Generate multiindex and datetimeindex for both the data and fill_data
multi = pd.MultiIndex.from_product([['A','B'],['one','two','three']])
idx1 = pd.DatetimeIndex(start='1990-01-01', periods=100, freq='d')
idx2 = pd.DatetimeIndex(start='1989-12-01', periods=200, freq='d')

#Construct dataframes
df1 = pd.DataFrame(data, idx1, multi)
df2 = pd.DataFrame(fill_data, idx2, multi)

#fill nans from df1 with df2
df1 = df1.fillna(df2, axis=1)

生成的帧如下所示:

In [167]:

df1.head()

Out[167]:
            A                                   B
            one         two         three       one         two         three
1990-01-01  1.000000    0.341803    0.694128    0.382164    0.326956    0.506616
1990-01-02  0.439024    0.552746    0.538489    0.003906    0.968498    0.816289
1990-01-03  0.200252    0.838014    0.805633    0.008980    0.269189    0.016243
1990-01-04  0.735120    0.384871    0.579268    0.561657    0.630314    0.361932
1990-01-05  0.938185    0.335212    0.678310    2.000000    0.819046    0.482535



In [168]:

df2.head()

Out[168]:
    A   B
    one     two     three   one     two     three
1989-12-01  1   2   3   1   2   3
1989-12-02  1   2   3   1   2   3
1989-12-03  1   2   3   1   2   3
1989-12-04  1   2   3   1   2   3
1989-12-05  1   2   3   1   2   3

所以这里的关键是数据帧的长度不同,但具有共同的标签,因为多索引列是相同的,并且 df1 中的时间戳标签在 df2 内。

结果如下:

In [165]:

df1

Out[165]:
            A                                   B
            one         two         three       one         two         three
1990-01-01  1.000000    0.341803    0.694128    0.382164    0.326956    0.506616
1990-01-02  0.439024    0.552746    0.538489    0.003906    0.968498    0.816289
1990-01-03  0.200252    0.838014    0.805633    0.008980    0.269189    0.016243
1990-01-04  0.735120    0.384871    0.579268    0.561657    0.630314    0.361932
1990-01-05  0.938185    0.335212    0.678310    2.000000    0.819046    0.482535
1990-01-06  0.609736    0.164815    0.295003    0.784388    3.000000    3.000000
1990-01-07  1.000000    0.394105    0.430608    0.782029    0.327485    0.855130
1990-01-08  0.573780    0.525845    0.147302    0.091022    3.000000    3.000000
1990-01-09  0.591646    0.651251    0.649255    0.205926    3.000000    0.606428
1990-01-10  0.988085    0.524769    0.481834    0.486241    0.629223    0.575843
1990-01-11  1.000000    0.586813    0.592252    0.309429    0.877121    0.547193
1990-01-12  0.853000    0.097981    0.970053    0.519838    0.828266    0.618965
1990-01-13  0.579778    0.805140    0.050559    0.432795    0.036241    0.081218
1990-01-14  0.055462    1.000000    0.159151    0.538137    3.000000    0.296754
1990-01-15  0.848238    0.697454    0.519403    0.232734    0.612487    0.891230
1990-01-16  0.808238    0.182904    0.480846    0.052806    0.900373    0.860274
1990-01-17  0.890997    0.346767    0.265168    0.486746    0.983999    0.104035
1990-01-18  0.673155    0.248853    0.245246    2.000000    0.965884    0.295021
1990-01-19  0.074864    0.714846    2.000000    0.046031    0.105930    0.641538
1990-01-20  1.000000    0.486893    0.464024    0.499484    0.794107    0.868002

如果仔细观察,您会发现 ('A','one') 和 ('A','two') 列中有等于 1 的值,('A',' 列中有等于 2 的值三') 和 ('B','one') 以及 ('B','two') 和 ('B','three') 中等于 3 的值。

预期的输出将是“一”列中的值 1、“二”列中的 2 等。

我在这里做错了吗?对我来说,这似乎是某种错误。

【问题讨论】:

嗯,你为什么不在github上为此打开一个问题。 我同意这种行为令人惊讶并且看起来像是一个错误。我可以用一个更简单的例子来重现它,而不是使用 DateTimeIndex 或 MultiIndex。 @Jeff:你能告诉我确切解释 df1.fillna(df2) 应该做什么的文档吗? pandas.pydata.org/pandas-docs/stable/generated/…。从技术上讲,这没有实现:)。它实际上非常复杂,因为您需要对齐 2 帧的块(dtypes);当然没有测试。让我们打开一个问题。也许在短期内会引发 NotImplementedError。 (如果你愿意,请做一个拉取请求) 作为一种解决方法,您可以使用df1.where(pd.notnull(df1), df2) 问题在这里:github.com/pydata/pandas/issues/8377 【参考方案1】:

此issue has been fixed 在最新版 Pandas 中。

使用 0.15.0 版您将能够做到这一点:

import pandas as pd
import numpy as np
from numpy import nan    

df = pd.DataFrame('a': [nan, 1, 2, nan, nan],
                   'b': [1, 2, 3, nan, nan],
                   'c': [nan, 1, 2, 3, 4],
                  index = list('VWXYZ'))
#     a   b   c
# V NaN   1 NaN
# W   1   2   1
# X   2   3   2
# Y NaN NaN   3
# Z NaN NaN   4

# df2 may have different index and columns
df2 = pd.DataFrame('a': [10, 20, 30, 40, 50],
                    'b': [50, 60, 70, 80, 90],
                    'c': list('ABCDE'),
                   index = list('VWXYZ'))
#     a   b  c
# V  10  50  A
# W  20  60  B
# X  30  70  C
# Y  40  80  D
# Z  50  90  E

现在,将 DataFrame 传递给fillna

result = df.fillna(df2)

产量

print(result)
#     a   b  c
# V  10   1  A
# W   1   2  1
# X   2   3  2
# Y  40  80  3
# Z  50  90  4

【讨论】:

以上是关于Pandas:具有多索引的 fillna() 方法 - NaN 填充了错误的列的主要内容,如果未能解决你的问题,请参考以下文章

具有多索引的 Pandas 样式对象

具有多索引的 Pandas 子数据透视表和总数据透视表

如何将 2 个未对齐的 Pandas 系列相乘并接收具有多索引的产品系列

带有多索引的 df.at 与 df.loc

Pandas Pivot Table - 重新组织多索引的顺序

Pandas groupby(),agg() - 如何在没有多索引的情况下返回结果?