DropMissingData#
从数据集中移除带有 nan 值的行是数据科学和机器学习项目中的常见做法。
您可能对使用 pandas dropna 很熟悉。基本上,您会取一个 pandas 数据框或 pandas 系列,应用 dropna,并消除那些在一列或多列中包含 nan 值的行。
这里,我们有一个该语法的示例:
import numpy as np
import pandas as pd
X = pd.DataFrame(dict(
x1 = [np.nan,1,1,0,np.nan],
x2 = ["a", np.nan, "b", np.nan, "a"],
))
X.dropna(inplace=True)
print(X)
之前的代码返回一个没有缺失值的数据框:
x1 x2
2 1.0 b
Feature-engine 的 DropMissingData()
在转换器中封装了 pandas 的 dropna,该转换器将在遵循 scikit-learn 的 fit
和 transform
功能的同时,删除包含 na 值的行。
这里我们有一个 DropMissingData()
语法的快照:
import pandas as pd
import numpy as np
from feature_engine.imputation import DropMissingData
X = pd.DataFrame(dict(
x1 = [np.nan,1,1,0,np.nan],
x2 = ["a", np.nan, "b", np.nan, "a"],
))
dmd = DropMissingData()
dmd.fit(X)
dmd.transform(X)
之前的代码返回一个没有缺失值的数据框:
x1 x2
2 1.0 b
DropMissingData()
因此允许你在任何 scikit-learn 特征工程工作流程中移除空值。
DropMissingData#
DropMissingData()
相对于 pandas 有一些优势:
它学习和存储应删除包含 nan 值的行的变量。
它可以在类似 Scikit-learn 的管道中使用。
使用 DropMissingData()
,你可以从数值和分类变量中删除 nan 值。换句话说,你可以从数值、分类或对象数据类型中移除空值。
您可以选择从所有列中删除 nan 值,或者仅从其中一部分列中删除。另外,如果某行包含超过一定百分比的 nan 值,您也可以选择删除该行。
让我们通过代码示例更好地说明 DropMissingData()
的功能。
Dropna#
让我们从导入 pandas 和 numpy 开始,并创建一个包含两列 nan 值的玩具数据框:
import numpy as np
import pandas as pd
from feature_engine.imputation import DropMissingData
X = pd.DataFrame(
dict(
x1=[2, 1, 1, 0, np.nan],
x2=["a", np.nan, "b", np.nan, "a"],
x3=[2, 3, 4, 5, 5],
)
)
y = pd.Series([1, 2, 3, 4, 5])
print(X.head())
下面我们看到新的数据框:
x1 x2 x3
0 2.0 a 2
1 1.0 NaN 3
2 1.0 b 4
3 0.0 NaN 5
4 NaN a 5
我们可以如下所示删除所有列中的 nan 值:
dmd = DropMissingData()
Xt = dmd.fit_transform(X)
Xt.head()
我们看到转换后的数据框没有空值:
x1 x2 x3
0 2.0 a 2
2 1.0 b 4
默认情况下,DropMissingData()
会在拟合过程中找到并存储在训练集中存在缺失数据的列。它们存储在这里:
dmd.variables_
['x1', 'x2']
这意味着每次我们对一个新的数据框应用 transform()
时,转换器将仅在那些列中删除带有 nan 值的行。
如果我们想强制 DropMissingData()
删除所有列中的缺失值,无论它们在拟合期间是否包含 nan 值,我们需要这样设置类:
dmd = DropMissingData(missing_only=False)
Xt = dmd.fit_transform(X)
现在,当我们探索参数 variables_
时,我们看到训练集中的所有变量都被存储,因此,将被用来移除 nan 值:
dmd.variables_
['x1', 'x2', 'x3']
在dropna后调整目标#
DropMissingData()
有一个选项可以从训练集和目标变量中移除包含 nan 的行。这样,我们可以获得一个与转换后的数据框对齐的目标。
方法 transform_x_y
从训练集中移除含有空值的行,然后重新对齐目标。让我们来看一下:
Xt, yt = dmd.transform_x_y(X, y)
Xt
下面我们看到没有 nan 的数据框:
x1 x2 x3
0 2.0 a 2
2 1.0 b 4
yt
在这里我们看到目标,这些行对应于转换后的数据框中的剩余行:
0 1
2 3
dtype: int64
让我们检查转换后的数据框和目标的形状是否相同:
Xt.shape, yt.shape
我们看到生成的训练集和目标各有2行,而不是原来的5行。
((2, 3), (2,))
返回包含 nan 的行#
当我们在生产环境中有一个模型时,了解哪些行被转换器删除可能是有用的。我们可以按如下方式获取该信息:
dmd.return_na_data(X)
上一个命令返回包含 nan 的行。换句话说,它与 transform()
或 pandas.dropna 相反。
x1 x2 x3
1 1.0 NaN 3
3 0.0 NaN 5
4 NaN a 5
从变量子集中删除缺失值#
我们可以选择仅从特定列或一组列中删除缺失数据。我们只需要将列名或列名传递给 variables
参数:
在这里,我们将从变量“x1”,“x3”中删除缺失值。
dmd = DropMissingData(variables=["x1", "x3"], missing_only=False)
Xt = dmd.fit_transform(X)
Xt.head()
下面,我们看到转换后的数据框。它删除了在“x1”中包含nan的行,我们看到那些在“x2”中包含nan的行仍然在数据框中:
x1 x2 x3
0 2.0 a 2
1 1.0 NaN 3
2 1.0 b 4
3 0.0 NaN 5
只有“x1”和“x3”中包含nan的行被移除。我们可以通过检查 variables_
参数来证实这一点:
重要
当你指定哪些变量应该被检查以删除包含 nan 的行时,请确保将参数 missing_only
设置为布尔值 False
。否则,DropMissingData()
将仅从你的列表中选择那些在训练集中显示了 nan 值的变量。
例如,看看当我们这样设置类时会发生什么:
dmd = DropMissingData(variables=["x1", "x3"], missing_only=True)
Xt = dmd.fit_transform(X)
dmd.variables_
注意,我们指示要从“x1”和“x3”中移除nan。然而,只有“x1”在X中有nan。因此,转换器学习到应该只从“x1”中移除nan:
['x1']
DropMissingData()
采用了列表中指示的2个变量,并且在拟合过程中仅存储了显示为nan的变量。这意味着在转换未来的数据框时,它将仅删除在“x1”中包含nan的行。
换句话说,如果你传递一个变量列表进行插补并设置 missing_only=True
,而你列表中的一些变量在训练集中没有缺失数据,那么在转换过程中,这些特定变量的缺失数据将不会被移除。
当 missing_only=True
时,转换器会“再次检查”输入的变量在训练集中是否有缺失数据。如果没有,则在 transform()
过程中忽略它们。
在未传递变量列表进行插补时,建议使用 missing_only=True
。
基于非NaN值百分比的dropna#
我们可以设置 DropMissingData()
以要求一行中保留一定百分比的非NA值。我们可以通过 threshold
参数来控制这种行为,该参数等同于 pandas.dropna 的 thresh
参数。
如果 threshold=1
,所有变量都需要有数据才能保留一行。如果 threshold=0.5
,50% 的变量需要有数据才能保留一行。如果 threshold=0.01
,10% 的变量需要有数据才能保留一行。如果 threshold=None
,任何变量中有 NA 的行都将被删除。
让我们通过一个例子来看看。我们创建一个新的数据框,其中每一行都有不同比例的非nan值。
X = pd.DataFrame(
dict(
x1=[2, 1, 1, np.nan, np.nan],
x2=["a", np.nan, "b", np.nan, np.nan],
x3=[2, 3, 4, 5, np.nan],
)
)
X
我们看到底部行在所有列中都有 nan,第 3 行在 3 列中有 2 列是 nan,而第 1 行在 1 个变量中有 nan:
x1 x2 x3
0 2.0 a 2.0
1 1.0 NaN 3.0
2 1.0 b 4.0
3 NaN NaN 5.0
4 NaN NaN NaN
现在,我们可以设置 DropMissingData()
来删除其值超过50%为nan的行:
dmd = DropMissingData(threshold=.5)
dmd.fit(X)
dmd.transform(X)
我们看到最后两行被丢弃了,因为它们超过50%的值是nan。
x1 x2 x3
0 2.0 a 2.0
1 1.0 NaN 3.0
2 1.0 b 4.0
相反,我们可以设置 class:DropMissingData()
来删除其值超过70%为nan的行,如下所示:
dmd = DropMissingData(threshold=.3)
dmd.fit(X)
dmd.transform(X)
现在我们看到只有最后一行被移除了。
x1 x2 x3
0 2.0 a 2.0
1 1.0 NaN 3.0
2 1.0 b 4.0
3 NaN NaN 5.0
Scikit-learn 兼容#
DropMissingData()
完全兼容 Scikit-learn API,因此你会发现一些在 Scikit-learn 转换器中常见的的方法,例如,get_feature_names_out()
方法用于获取转换后的数据框中的变量名称。
管道#
当我们从数据框中删除缺失值后,我们需要重新对齐目标。我们之前看到可以通过使用 transform_x_y
方法来实现这一点。
我们也可以在管道内自动将目标与生成的数据框对齐,通过利用 Feature-engine 的管道。
首先,让我们导入必要的库:
import numpy as np
import pandas as pd
from feature_engine.imputation import DropMissingData
from feature_engine.encoding import OrdinalEncoder
from feature_engine.pipeline import Pipeline
让我们创建一个新的数据框,其中某些行包含 nan 值,两个数值变量和一个分类变量,以及其对应的目标变量:
X = pd.DataFrame(
dict(
x1=[2, 1, 1, 0, np.nan],
x2=["a", np.nan, "b", np.nan, "a"],
x3=[2, 3, 4, 5, 5],
)
)
y = pd.Series([1, 2, 3, 4, 5])
X.head()
下面,我们看到了生成的数据框:
x1 x2 x3
0 2.0 a 2
1 1.0 NaN 3
2 1.0 b 4
3 0.0 NaN 5
4 NaN a 5
现在让我们设置一个管道,首先删除缺失值,然后使用序数编码对分类变量进行编码:
pipe = Pipeline(
[
("drop", DropMissingData()),
("enc", OrdinalEncoder(encoding_method="arbitrary")),
]
)
pipe.fit_transform(X, y)
当我们应用 fit
和 transform
或 fit_transform
时,我们只会得到转换后的训练集:
x1 x2 x3
0 2.0 0 2
2 1.0 1 4
为了获取变换训练集和目标,我们使用 transform_x_y
:
pipe.fit(X,y)
Xt, yt = pipe.transform_x_y(X, y)
Xt
这里我们看到转换后的训练集:
x1 x2 x3
0 2.0 0 2
2 1.0 1 4
yt
在这里我们看到重新对齐的目标变量:
0 1
2 3
最后,让我们在管道中添加一个估计器:
import numpy as np
import pandas as pd
from sklearn.linear_model import Lasso
from feature_engine.imputation import DropMissingData
from feature_engine.encoding import OrdinalEncoder
from feature_engine.pipeline import Pipeline
df = pd.DataFrame(
dict(
x1=[2, 1, 1, 0, np.nan],
x2=["a", np.nan, "b", np.nan, "a"],
x3=[2, 3, 4, 5, 5],
)
)
y = pd.Series([1, 2, 3, 4, 5])
pipe = Pipeline(
[
("drop", DropMissingData()),
("enc", OrdinalEncoder(encoding_method="arbitrary")),
("lasso", Lasso(random_state=2))
]
)
pipe.fit(df, y)
pipe.predict(df)
array([2., 2.])
Dropna 还是 fillna?#
DropMissingData()
具有与 pandas.series.dropna
或 pandas.dataframe.dropna
相同的功能。如果你想使用与 pandas.fillna
兼容的功能,请查看我们的其他插补转换器。
删除包含 nan 的列#
目前,Feature-engine 没有能够找到缺失值达到一定百分比的列并自动删除它们的转换器。相反,你可以手动找到这些列,然后借助选择模块中的 DropFeatures
来删除它们。
另见#
查看我们关于 LagFeatures
和 WindowFeatures
的教程,了解如何将 DropMissingData()
与滞后或滚动窗口结合使用,以创建用于预测的特征。
教程、书籍和课程#
在以下Jupyter笔记本中,在我们的配套Github仓库中,您将找到更多使用 DropMissingData()
的示例。
有关此功能和其他特征工程方法的教程,请查看我们的在线课程:
或者阅读我们的书:
我们的书籍和课程都适合初学者和更高级的数据科学家。通过购买它们,您正在支持 Feature-engine 的主要开发者 Sole。