Python ColumnTransformer 设置WithCopyWarning

标签 python pandas numpy dataframe scikit-learn

使用 scikit-learn ColumnTransformer 对 DataFrame 应用转换时,我收到 SettingWithCopyWarning,但我不确定这是为什么。

这是我的代码。

import pandas as pd
import numpy as np
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import FunctionTransformer

import warnings
warnings.filterwarnings("always")

def filling_nan(frame):
    """Fills columns that have null values with zeros."""
    frame.fillna(0, inplace=True)
    return frame

def as_is(frame):
    """Returns the DataFrame as it is."""
    return frame

np.random.seed(1337)
df = pd.DataFrame(data=np.random.random(size=(5,5)), columns=list('ABCDE'))
df = df.applymap(lambda x: np.nan if x<0.15 else x) # Set a few numbers in the dataframe to NaN.

print(df)

这就是原始 DataFrame 的样子...

          A         B         C         D         E
0  0.262025  0.158684  0.278127  0.459317  0.321001
1  0.518393  0.261943  0.976085  0.732815       NaN
2  0.386275  0.628501       NaN  0.983549  0.443225
3  0.789558  0.794119  0.361262  0.416104  0.584258
4  0.760172  0.187808  0.288167  0.670219  0.499648

然后,我在 ColumnTransformer 中创建步骤,并指定列的索引而不是列名称。

step_filling_nans = ('filling_nans', FunctionTransformer(filling_nan, validate=False), [2, 4])
step_as_is = ('as_is', FunctionTransformer(as_is, validate=False), [0, 1, 3])

然后我创建 ColumnTransformer...

trans = ColumnTransformer(
    transformers=[
        step_filling_nans
        , step_as_is # I could pass 'passthrough' to the remainder keyword instead of doing this step.
    ], remainder='drop')

最后,我打印将 ColumnTransformer 应用到 DataFrame 的结果。

print(trans.fit_transform(df))

这是转换的输出。 ColumnTransformer 按预期返回一个 numpy 数组(分别是第一个和第二个列“C”和“E”),但我不明白为什么我收到 SettingWithCopy 警告。

[[0.27812652 0.32100054 0.26202468 0.15868397 0.45931689]
 [0.97608528 0.         0.51839282 0.26194293 0.73281455]
 [0.         0.44322487 0.38627507 0.62850118 0.98354861]
 [0.36126157 0.58425813 0.78955834 0.79411858 0.41610394]
 [0.28816715 0.49964826 0.76017177 0.18780841 0.67021886]]

/bigdisk0/users/belladam/.conda/envs/day_zero_retention/lib/python3.6/site-packages/pandas/core/frame.py:3787: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  downcast=downcast, **kwargs)

我已经设法通过稍微更改 fill_nan() 函数来修复它,但我不明白为什么会修复它。

def filling_nan(frame):
    """Fills columns that have null values with zeros."""
    frame = frame.fillna(0)
    return frame

我无法在使用 ColumnTransformer 之外重现结果,所以想知道这是否与此有关?

最佳答案

我相信 ColumnTransformer 会以这种方式运行,因为它能够并行运行与不同列相关的不同转换。你可以看看sklearn code itself here ,在第 448 行。如果您想使用并行化,那么在同一个对象(相同的内存位置)上工作并不真正安全。

通过避免使用inplace,您实际上是在复制原始对象,这解决了问题:

def filling_nan(frame):
    """Fills columns that have null values with zeros."""
    frame = frame.fillna(0)
    return frame

def filling_nan_inplace(frame):
    """Fills columns that have null values with zeros."""
    frame.fillna(0, inplace=True)
    return frame

print(id(df))
print(id(filling_nan_inplace(df)))
print(id(filling_nan(df)))

输出:

2088604584760
2088604584760
2088604583304

关于Python ColumnTransformer 设置WithCopyWarning,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59577674/

相关文章:

python - 子进程和额外的参数

python - 如何将正则表达式与 pandas series.find 函数一起使用

python - 将列表转换为 Pandas 时间序列

python - 为什么 hstack() 复制数据而 hsplit() 在其上创建 View ?

Python 3 - urllib.request - HTTPError

python - PyPI 包的安装统计数量?

python - 无法使用带有 *args 参数的函数的 jit 编译函数

python - 如何在 Pandas 中的 transpose() 之后删除多余的行(或列)

python - numpy 中的矢量化矩阵曼哈顿距离

python - 为每个循环创建新的 numpy 数组数据集