使用 fancyimpute 和 pandas 进行数据插补

Posted

技术标签:

【中文标题】使用 fancyimpute 和 pandas 进行数据插补【英文标题】:Data imputation with fancyimpute and pandas 【发布时间】:2017-12-27 14:23:33 【问题描述】:

我有一个大熊猫数据名气df。它有很多缺失。删除行/或 col-wise 不是一种选择。估算中位数、均值或最常见的值也不是一种选择(因此,不幸的是,用pandas 和/或scikit 进行估算并不能奏效)。

我遇到了一个名为fancyimpute 的看起来很简洁的包(你可以找到它here)。但我有一些问题。

这是我的工作:

#the neccesary imports
import pandas as pd
import numpy as np
from fancyimpute import KNN

# df is my data frame with the missings. I keep only floats
df_numeric = = df.select_dtypes(include=[np.float])

# I now run fancyimpute KNN, 
# it returns a np.array which I store as a pandas dataframe
df_filled = pd.DataFrame(KNN(3).complete(df_numeric))

然而,df_filled 不知何故是一个单一的向量,而不是填充的数据框。如何通过插补获取数据框?

更新

我意识到,fancyimpute 需要 numpay array。因此,我使用as_matrix()df_numeric 转换为一个数组。

# df is my data frame with the missings. I keep only floats
df_numeric = df.select_dtypes(include=[np.float]).as_matrix()

# I now run fancyimpute KNN, 
# it returns a np.array which I store as a pandas dataframe
df_filled = pd.DataFrame(KNN(3).complete(df_numeric))

输出是一个缺少列标签的数据框。有什么方法可以检索标签?

【问题讨论】:

df_filled.columns = df_numeric.columns 应该这样做。顺便说一句,这看起来确实是一个有趣的包 我也这么认为!我对 pandas fillna()sklearn.preprocessing.Imputer 有点失望。我没有遇到可以充分利用它们的情况。我认为,他们将极大地受益于一些更复杂的方法来估算/插入缺失数据。 【参考方案1】:

在您的代码后添加以下行:

df_filled.columns = df_numeric.columns
df_filled.index = df_numeric.index

【讨论】:

谢谢你,米里亚姆!我满脑子都是在fancyimpute 文档中找到一些我忘记了简单解决方案的东西。完美答案!【参考方案2】:

我看到了对花哨的 impute 和 pandas 的挫败感。这是一个使用递归覆盖方法的相当基本的包装器。接收并输出一个数据框 - 完整的列名。这类包装器适用于管道。

from fancyimpute import SoftImpute

class SoftImputeDf(SoftImpute):
    """DataFrame Wrapper around SoftImpute"""

    def __init__(self, shrinkage_value=None, convergence_threshold=0.001,
                 max_iters=100,max_rank=None,n_power_iterations=1,init_fill_method="zero",
                 min_value=None,max_value=None,normalizer=None,verbose=True):

        super(SoftImputeDf, self).__init__(shrinkage_value=shrinkage_value, 
                                           convergence_threshold=convergence_threshold,
                                           max_iters=max_iters,max_rank=max_rank,
                                           n_power_iterations=n_power_iterations,
                                           init_fill_method=init_fill_method,
                                           min_value=min_value,max_value=max_value,
                                           normalizer=normalizer,verbose=False)



    def fit_transform(self, X, y=None):

        assert isinstance(X, pd.DataFrame), "Must be pandas dframe"

        for col in X.columns:
            if X[col].isnull().sum() < 10:
                X[col].fillna(0.0, inplace=True)

        z = super(SoftImputeDf, self).fit_transform(X.values)
        return pd.DataFrame(z, index=X.index, columns=X.columns)

【讨论】:

【参考方案3】:

我非常欣赏@jander081 的方法,并对其进行了一点扩展以处理设置分类列。我遇到了一个问题,即分类列在训练期间会被取消设置并产生错误,因此修改代码如下:

from fancyimpute import SoftImpute
import pandas as pd

class SoftImputeDf(SoftImpute):
    """DataFrame Wrapper around SoftImpute"""

    def __init__(self, shrinkage_value=None, convergence_threshold=0.001,
                 max_iters=100,max_rank=None,n_power_iterations=1,init_fill_method="zero",
                 min_value=None,max_value=None,normalizer=None,verbose=True):

        super(SoftImputeDf, self).__init__(shrinkage_value=shrinkage_value, 
                                           convergence_threshold=convergence_threshold,
                                           max_iters=max_iters,max_rank=max_rank,
                                           n_power_iterations=n_power_iterations,
                                           init_fill_method=init_fill_method,
                                           min_value=min_value,max_value=max_value,
                                           normalizer=normalizer,verbose=False)



    def fit_transform(self, X, y=None):

        assert isinstance(X, pd.DataFrame), "Must be pandas dframe"

        for col in X.columns:
            if X[col].isnull().sum() < 10:
                X[col].fillna(0.0, inplace=True)

        z = super(SoftImputeDf, self).fit_transform(X.values)
        df = pd.DataFrame(z, index=X.index, columns=X.columns)
        cats = list(X.select_dtypes(include='category'))
        df[cats] = df[cats].astype('category')

        # return pd.DataFrame(z, index=X.index, columns=X.columns)
        return df

【讨论】:

当我调用 fit_transform 方法时,我应该传递什么参数来估算它,我使用的是 CSV 文件【参考方案4】:
df=pd.DataFrame(data=mice.complete(d), columns=d.columns, index=d.index)

fancyimpute 对象(无论是鼠标还是 KNN)的 .complete() 方法返回的 np.array 作为其 cols 和索引与原始数据相同的 pandas 数据帧的内容 (argument data=) 提供框架。

【讨论】:

你能解释一下这个答案吗? 当然。由fancyimpute 对象(无论是mice 还是KNN)的.complete() 方法返回的np.array 作为其cols 和indexes 与原始数据相同的pandas 数据框的内容(参数data=)提供框架

以上是关于使用 fancyimpute 和 pandas 进行数据插补的主要内容,如果未能解决你的问题,请参考以下文章

Anaconda 中的 FancyImpute 安装

无法安装 fancyimpute 以在 Jupyter 中使用

python笔记:fancyimpute

如何在 Python 中使用 Pandas 按列分组

如何使用Python的Pandas库绘制折线图

在Python中按日期对excel文件进​​行排序[关闭]