熊猫不会在原地填写na()
Posted
技术标签:
【中文标题】熊猫不会在原地填写na()【英文标题】:Pandas won't fillna() inplace 【发布时间】:2014-03-26 17:46:53 【问题描述】:我正在尝试在数据框中的 4 个特定列上用“”填充 NA,这些列是字符串/对象类型。我可以在 fillna() 时将这些列分配给一个新变量,但是当我 fillna() 就地时,基础数据不会改变。
a_n6 = a_n6[["PROV LAST", "PROV FIRST", "PROV MID", "SPEC NM"]].fillna("")
a_n6
给我:
<class 'pandas.core.frame.DataFrame'>
Int64Index: 1542 entries, 0 to 3611
Data columns (total 4 columns):
PROV LAST 1542 non-null values
PROV FIRST 1542 non-null values
PROV MID 1542 non-null values
SPEC NM 1542 non-null values
dtypes: object(4)
但是
a_n6[["PROV LAST", "PROV FIRST", "PROV MID", "SPEC NM"]].fillna("", inplace=True)
a_n6
给我:
<class 'pandas.core.frame.DataFrame'>
Int64Index: 1542 entries, 0 to 3611
Data columns (total 7 columns):
NPI 1103 non-null values
PIN 1542 non-null values
PROV FIRST 1541 non-null values
PROV LAST 1542 non-null values
PROV MID 1316 non-null values
SPEC NM 1541 non-null values
flag 439 non-null values
dtypes: float64(2), int64(1), object(4)
这只是一排,但仍然令人沮丧。我做错了什么?
【问题讨论】:
我也遇到过一些inplace=True
似乎被忽略的函数。虽然这不是您的问题,但在进行故障排除时值得牢记。
【参考方案1】:
您正在填写一份副本(然后您看不到)
要么:
不要fillna
inplace(就地做某事不会提高性能)
例如
a_n6[["PROV LAST", "PROV FIRST", "PROV MID", "SPEC NM"]] = a_n6[["PROV LAST", "PROV FIRST", "PROV MID", "SPEC NM"]].fillna("")
或者最好
a_n6.fillna('PROV LAST': '', 'PROV FIRST': '',
'PROV MID': '', 'SPEC NM': '', inplace=True)
首先将副本分配给新变量(a_n6[[list_of_fileds]]
是多类型对象中的副本),请参见此处:http://pandas.pydata.org/pandas-docs/stable/indexing.html#returning-a-view-versus-a-copy
这里有更深入的解释 Pandas: Chained assignments
【讨论】:
我认为 inplace 参数应该防止它填充副本。如果inplace
arg 不改变函数的行为,它的意义何在?
那么为什么 fillna() 甚至允许 inplace 呢?
如果您使用 .loc,Inplace 将起作用。如果您正在处理副本,则 Inplace 不应该工作。请参阅 Jeff 包含的链接。它不适用于字段列表(例如 df.loc[:,[list of fields]]),但适用于切片或单个字段。另请参阅github.com/pandas-dev/pandas/issues/11984 了解有关此的一些详细信息。
我刚刚在一个 20Gb 数据集上运行了 fillna,就地并得到了“未实现”错误。我没有看到关于“没有性能提升”的咆哮。我没有另一个 20Gb 内存来保存临时副本。 Inplace 将非常有益。【参考方案2】:
使用dict
作为value
的参数fillna()
正如@rhkarls 对@Jeff 的回答的评论中提到的,使用索引到列列表的.loc
将不支持inplace
操作,我也觉得这很令人沮丧。这是一种解决方法。
例子:
import pandas as pd
import numpy as np
df = pd.DataFrame('a':[1,2,3,4,np.nan],
'b':[6,7,8,np.nan,np.nan],
'x':[11,12,13,np.nan,np.nan],
'y':[16,np.nan,np.nan,19,np.nan])
print(df)
# a b x y
#0 1.0 6.0 11.0 16.0
#1 2.0 7.0 12.0 NaN
#2 3.0 8.0 13.0 NaN
#3 4.0 NaN NaN 19.0
#4 NaN NaN NaN NaN
假设我们只想为x
和y
发送fillna
,不是 a
和b
。
我希望使用 .loc
可以工作(就像在作业中一样),但它没有,如前所述:
# doesn't work
df.loc[:,['x','y']].fillna(0, inplace=True)
print(df) # nothing changed
但是,documentation 表示 fillna()
的 value
参数可以是:
或者是一个 dict/Series/DataFrame 值,指定用于每个索引(对于 Series)或列(对于 DataFrame)的值。 (不在 dict/Series/DataFrame 中的值不会被填充)。
事实证明,使用值的字典会起作用:
# works
df.fillna('x':0, 'y':0, inplace=True)
print(df)
# a b x y
#0 1.0 6.0 11.0 16.0
#1 2.0 7.0 12.0 0.0
#2 3.0 8.0 13.0 0.0
#3 4.0 NaN 0.0 19.0
#4 NaN NaN 0.0 0.0
另外,如果您的子集中有很多列,您可以使用字典推导式,如下所示:
df.fillna(x:0 for x in ['x','y'], inplace=True) # also works
【讨论】:
【参考方案3】:一种解决方法是将 fillna 结果保存在另一个变量中,然后像这样将其分配回去:
na_values_filled = X.fillna(0)
X = na_values_filled
我的确切示例(否则我无法开始工作)是我只想填写每个组的第一行的情况。像这样:
groups = one_train.groupby("installation_id")
first_indexes_filled = one_train.loc[groups.apply(pd.DataFrame.first_valid_index), 'clicks'].fillna(0)
one_train.loc[groups.apply(pd.DataFrame.first_valid_index), 'clicks'] = first_indexes_filled
我的情况可能过于复杂,但我认为一般的“保存结果,然后分配回”方法应该可以作为失败的 inplace=True 的解决方法
【讨论】:
【参考方案4】:最佳答案给了我SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame
,所以这就是我最终得到的。它可以工作并且不会发出任何警告:
fill_dict = x: 0 for x in columns_of_interest
df.loc[:, columns_of_interest].fillna(fill_dict, inplace=True)
【讨论】:
【参考方案5】:“使用 dict 作为值参数”答案对我不起作用,但一个足够简单的解决方法是使用:
for n in ["PROV LAST", "PROV FIRST", "PROV MID", "SPEC NM"]:
a_n6[n].fillna("", inplace=True)
a_n6
【讨论】:
以上是关于熊猫不会在原地填写na()的主要内容,如果未能解决你的问题,请参考以下文章