Python中的矩阵补全
假设我有一个矩阵:Python中的矩阵补全,python,numpy,machine-learning,scikit-learn,mathematical-optimization,Python,Numpy,Machine Learning,Scikit Learn,Mathematical Optimization,假设我有一个矩阵: > import numpy as nap > a = np.random.random((5,5)) array([[ 0.28164485, 0.76200749, 0.59324211, 0.15201506, 0.74084168], [ 0.83572213, 0.63735993, 0.28039542, 0.19191284, 0.48419414], [ 0.99967476, 0.8029097 ,
> import numpy as nap
> a = np.random.random((5,5))
array([[ 0.28164485, 0.76200749, 0.59324211, 0.15201506, 0.74084168],
[ 0.83572213, 0.63735993, 0.28039542, 0.19191284, 0.48419414],
[ 0.99967476, 0.8029097 , 0.53140614, 0.24026153, 0.94805153],
[ 0.92478 , 0.43488547, 0.76320656, 0.39969956, 0.46490674],
[ 0.83315135, 0.94781119, 0.80455425, 0.46291229, 0.70498372]])
我用np.NaN
在上面打了几个洞,例如:
> a[(1,4,0,3),(2,4,2,0)] = np.NaN;
array([[ 0.80327707, 0.87722234, nan, 0.94463778, 0.78089194],
[ 0.90584284, 0.18348667, nan, 0.82401826, 0.42947815],
[ 0.05913957, 0.15512961, 0.08328608, 0.97636309, 0.84573433],
[ nan, 0.30120861, 0.46829231, 0.52358888, 0.89510461],
[ 0.19877877, 0.99423591, 0.17236892, 0.88059185, nan ]])
我想使用矩阵其余条目中的信息填写nan
条目。例如,使用出现nan
条目的列的平均值
更一般地说,Python中是否有用于的库?(例如,沿着……线的东西)
背景:
这个问题经常出现在机器学习中。例如,在分类/回归或中处理缺少的功能时(例如,请参阅和上的Netflix问题)您只需使用
熊猫
import pandas as pd
DF = pd.DataFrame(a)
col_means = DF.apply(np.mean, 0)
DF.fillna(value=col_means)
你可以用纯numpy来做,但它更恶心
from scipy.stats import nanmean
>>> a
array([[ 0.70309466, 0.53785006, nan, 0.49590115, 0.23521493],
[ 0.29067786, 0.48236186, nan, 0.93220001, 0.76261019],
[ 0.66243065, 0.07731947, 0.38887545, 0.56450533, 0.58647126],
[ nan, 0.7870873 , 0.60010096, 0.88778259, 0.09097726],
[ 0.02750389, 0.72328898, 0.69820328, 0.02435883, nan]])
>>> mean=nanmean(a,axis=0)
>>> mean
array([ 0.42092677, 0.52158153, 0.56239323, 0.58094958, 0.41881841])
>>> index=np.where(np.isnan(a))
>>> a[index]=np.take(mean,index[1])
>>> a
array([[ 0.70309466, 0.53785006, 0.56239323, 0.49590115, 0.23521493],
[ 0.29067786, 0.48236186, 0.56239323, 0.93220001, 0.76261019],
[ 0.66243065, 0.07731947, 0.38887545, 0.56450533, 0.58647126],
[ 0.42092677, 0.7870873 , 0.60010096, 0.88778259, 0.09097726],
[ 0.02750389, 0.72328898, 0.69820328, 0.02435883, 0.41881841]])
运行一些计时:
import time
import numpy as np
import pandas as pd
from scipy.stats import nanmean
a = np.random.random((10000,10000))
col=np.random.randint(0,10000,500)
row=np.random.randint(0,10000,500)
a[(col,row)]=np.nan
a1=np.copy(a)
%timeit mean=nanmean(a,axis=0);index=np.where(np.isnan(a));a[index]=np.take(mean,index[1])
1 loops, best of 3: 1.84 s per loop
%timeit DF=pd.DataFrame(a1);col_means = DF.apply(np.mean, 0);DF.fillna(value=col_means)
1 loops, best of 3: 5.81 s per loop
#Surprisingly, issue could be apply looping over the zero axis.
DF=pd.DataFrame(a2)
%timeit col_means = DF.apply(np.mean, 0);DF.fillna(value=col_means)
1 loops, best of 3: 5.57 s per loop
我不相信numpy内置了数组完成例程;然而,熊猫确实如此。查看帮助主题。类似的问题已被解决。你需要的是一个特殊的情况。不幸的是,numpy和scipy都没有用于此的内置例程。然而,OpenCV有一个函数,但它只适用于8位图像 具有可供您使用的
replace_nans
功能。(对于Cython版本,如果不想安装整个库,您可以重新打包。)它比其他答案中建议的纯平均值或旧值传播更灵活(例如,您可以定义不同的权重函数、内核大小等)
使用@Ophion的示例,我将replace_nans
与nanmean
和Pandas解决方案进行了比较:
import numpy as np
import pandas as pd
from scipy.stats import nanmean
a = np.random.random((10000,10000))
col=np.random.randint(0,10000,500)
row=np.random.randint(0,10000,500)
a[(col,row)]=np.nan
a1=np.copy(a)
%timeit new_array = replace_nans(a1, 10, 0.5, 1.)
1 loops, best of 3: 1.57 s per loop
%timeit mean=nanmean(a,axis=0);index=np.where(np.isnan(a));a[index]=np.take(mean,index[1])
1 loops, best of 3: 2.23 s per loop
%timeit DF=pd.DataFrame(a1);col_means = DF.apply(np.mean, 0);DF.fillna(value=col_means)
1 loops, best of 3: 7.23 s per loop
replace_nans
解决方案可以说更好更快。如果您安装了最新的scikit learn,版本0.14a1,您可以使用其全新的插补器
类:
>>> from sklearn.preprocessing import Imputer
>>> imp = Imputer(strategy="mean")
>>> a = np.random.random((5,5))
>>> a[(1,4,0,3),(2,4,2,0)] = np.nan
>>> a
array([[ 0.77473361, 0.62987193, nan, 0.11367791, 0.17633671],
[ 0.68555944, 0.54680378, nan, 0.64186838, 0.15563309],
[ 0.37784422, 0.59678177, 0.08103329, 0.60760487, 0.65288022],
[ nan, 0.54097945, 0.30680838, 0.82303869, 0.22784574],
[ 0.21223024, 0.06426663, 0.34254093, 0.22115931, nan]])
>>> a = imp.fit_transform(a)
>>> a
array([[ 0.77473361, 0.62987193, 0.24346087, 0.11367791, 0.17633671],
[ 0.68555944, 0.54680378, 0.24346087, 0.64186838, 0.15563309],
[ 0.37784422, 0.59678177, 0.08103329, 0.60760487, 0.65288022],
[ 0.51259188, 0.54097945, 0.30680838, 0.82303869, 0.22784574],
[ 0.21223024, 0.06426663, 0.34254093, 0.22115931, 0.30317394]])
在此之后,您可以使用imp.transform
对其他数据执行相同的转换,使用imp
从a
学习的平均值。插补器与scikit learnPipeline
对象关联,因此您可以在分类或回归管道中使用它们
如果您想等待一个稳定的版本,那么0.14应该在下周发布
完整披露:我是一名scikit learn core开发人员您想要的确切方法(Candes和Recht,2008)可在位于此处的
FancyComputer
库中找到
我看到了很好的结果。谢天谢地,在过去的一年里,他们将autodiff和SGD后端从在引擎盖下使用Theano的downhill改为keras。此库中也提供了该算法()。SciKit Learn的插补器()
不包括此算法。文档中没有,但您可以使用pip
安装fancyicomputer
:
pip install fancyimpute
谢谢顺便说一下,文档中讨论了
bfill
、backfill
、pad
和ffill
。我在哪里可以阅读更多关于这些方法的信息?()bfill
是backfill
的缩写,ffill
是pad
的“缩写”。我不认为有太多的文档,但代码是另外的,您应该阅读pandas missing data help.。除非我缺少某个replace_nans
用加权平均值填充nans
,这并不等同于用列的平均值替换nans
。对于4个循环中的4个if语句,我不确定如果您的数组包含许多nan,它会快多少。如果您将NaN的数量从500更改为5000,我会非常好奇时间安排。@Opion:您是对的,它不会用列的平均值替换NaN。但这就是问题所在:列平均值并不是最佳替代值。出于好奇,我刚刚使用np.random.randint(0100005000)
重新运行了col
和行的计时replace_nans
现在需要1.55秒,nanmean
需要2.15秒。所以,非常相似……您确定它在10次迭代中替换了所有的nan
?我很抱歉对此表示怀疑——乍一看,代码似乎不是一种有效的方法。它似乎在10次迭代中取代了所有的NAN。你自己试试吧。这里的要点不是找到在替换最大数量的NAN时更快的代码,而是找到缺失值的最佳估计。修复不是为NAN占很大比例的图像设计的,但它无法修复所有未知值的行。此外,还有更先进的矩阵完成方法吗?对于插补器,它仅根据中值、平均值或频繁值推断值。
pip install fancyimpute