使用numpy.genfromtxt填充缺失值

6

尽管前面的问题给出了建议:

使用numpy.genfromtxt()将-9999作为缺失值

使用numpy中的genfromtxt导入包含缺失值的csv数据

但我仍然无法处理以缺失值结尾的文本文件,

a.txt:

1 2 3
4 5 6
7 8

我尝试了多种选项的排列,包括missing_valuesfilling_values,但无法使其正常工作:

import numpy as np

sol = np.genfromtxt("a.txt", 
                    dtype=float,
                    invalid_raise=False, 
                    missing_values=None,
                    usemask=True,
                    filling_values=0.0)
print sol

我想要得到的是:
[[1.0 2.0 3.0]
 [4.0 5.0 6.0]
 [7.0 8.0 0.0]]

但是我得到的是:
/usr/local/lib/python2.7/dist-packages/numpy/lib/npyio.py:1641: ConversionWarning: Some errors were detected !
    Line #3 (got 2 columns instead of 3)
  warnings.warn(errmsg, ConversionWarning)
[[1.0 2.0 3.0]
 [4.0 5.0 6.0]]

是否可以更改分隔符? - Daniel
@Ophion 不,假设文本文件是固定的。我当然可以用普通的Python加载文件,并使用几个str.split,但问题是如何使用numpy.genfromtxt完成相同的操作。 - Hooked
你对使用pandas解决方案感兴趣吗?(非常简单) - unutbu
Numpy的IOtools使用line.split(delimiter)。除非列跨越的字符数是固定的,否则我不确定是否有其他方法。正如提到的那样,py pandas真的很棒 - 一旦我开始使用它,我的生活变得简单多了。 - Daniel
从文档[docs](http://docs.scipy.org/doc/numpy/reference/generated/numpy.genfromtxt.html)中可以看出,“当空格被用作分隔符,或者当没有给出输入分隔符时,在两个字段之间不应该有任何缺失数据。” 你不能做你想做的事。 - Gerrat
3个回答

8

使用pandas

import pandas as pd

df = pd.read_table('data', sep='\s+', header=None)
df.fillna(0, inplace=True)
print(df)
#    0  1  2
# 0  1  2  3
# 1  4  5  6
# 2  7  8  0

pandas.read_table 会用 NaN 替换缺失数据。您可以使用 df.fillna 将这些 NaN 替换为其他值。

df 是一个 pandas.DataFrame。您可以使用 df.values 访问底层的 NumPy 数组:

print(df.values)
# [[ 1.  2.  3.]
#  [ 4.  5.  6.]
#  [ 7.  8.  0.]]

你可以在 pd.read_table 中添加 dtype=float 关键字以获取所需的数据类型...不过+1。 - dawg
我感谢您的回答,并将来研究pandas。这个问题特别涉及到genformtxt和扩展numpy,所以我会接受其他答案。 - Hooked

4
问题在于numpy不喜欢不规则的数组。由于文件的最后一行第三个位置没有字符,因此genfromtxt甚至不知道它是要解析的内容,更不用说该如何处理它了。如果缺失值有填充符(任何填充符),例如:
1 2 3
4 5 6
7 8 ''

那么您将能够:

sol = np.genfromtxt("a.txt",
                dtype=float,
                invalid_raise=False,
                missing_values='',
                usemask=False,
                filling_values=0.0)

并且: sol

array([[  1.,   2.,   3.],
       [  4.,   5.,   6.],
       [  7.,   8.,  nan]])

不幸的是,如果无法使文件中的列统一,您可能只能逐行解析。

另一个可能性是,如果所有“短”行都在末尾...在这种情况下,您可以利用'usecols'标志解析所有统一的列,然后使用'skip_footer'标志解析剩余的列,同时跳过那些不可用的列:

sol = np.genfromtxt("a.txt",
                dtype=float,
                invalid_raise=False,
                usemask=False,
                filling_values=0.0,
                usecols=(0,1))
sol
array([[ 1.,  2.],
   [ 4.,  5.],
   [ 7.,  8.]])

sol2 = np.genfromtxt("a.txt",
                dtype=float,
                invalid_raise=False,
                usemask=False,
                filling_values=0.0,
                usecols=(2,),
                skip_footer=1)
sol2
array([ 3.,  6.])

然后将数组组合起来并添加填充值:

sol2=np.append(sol2, 0.0)
sol2=sol2.reshape(3,1)
sol=np.hstack([sol,sol2])
sol
array([[ 1.,  2.,  3.],
   [ 4.,  5.,  6.],
   [ 7.,  8.,  0.]])

谢谢,我没有考虑到usecols的解决方案,通常我应该提前知道哪一列会丢失,而且错误行总是在最后。 - Hooked

-1
根据我的经验,最好的方法是手动解析,这个函数对我有效,虽然速度可能较慢,但一般足够快。
def manual_parsing(filename,delim,dtype):
    out = list()
    lengths = list()
    with open(filename,'r') as ins:
        for line in ins:
            l = line.split(delim)
            out.append(l)
            lengths.append(len(l))
    lim = np.max(lengths)
    for l in out:
        while len(l)<lim:
            l.append("nan")
    return np.array(out,dtype=dtype)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接