从文本字段创建掩码数组
numpy的文档中展示了如何使用ma.masked
来屏蔽已有的值,这个操作是在数组创建之后进行的,或者是从看起来有效的数据类型(如果dtype=int
就是整数)列表中创建一个屏蔽数组。我现在想从一个文件中读取数据(这需要一些文本处理),但最终我会得到一个包含字符串的列表(或元组),我想把它转换成一个数字(浮点数)数组。
数据的一个例子可能是textdata='1\t2\t3\n4\t\t6'
(经过清理后的典型平面文本格式)。
我遇到的一个问题是,缺失的值可能会被编码为'',而当我尝试使用dtype参数将其转换为浮点数时,会出现以下问题:
ValueError: setting an array element with a sequence.
所以我创建了这个函数:
def makemaskedarray(X,missing='',fillvalue='-999.',dtype=float):
arr = lambda x: x==missing and fillvalue or x
mask = lambda x: x==missing and 1 or 0
triple = dict(zip(('data','mask','dtype'),
zip(*[(map(arr,x),map(mask,x)) for x in X])+
[dtype]))
return ma.array(**triple)
这个函数似乎能解决问题:
>>> makemaskedarray([('1','2','3'),('4','','6')])
masked_array(data =
[[1.0 2.0 3.0]
[4.0 -- 6.0]],
mask =
[[False False False]
[False True False]],
fill_value = 1e+20)
这样做对吗?或者有没有内置的函数可以用?
1 个回答
1
你现在的做法是可以的。不过,如果你想让代码更易读,可以考虑不先创建一个临时的“triple
”字典,然后再扩展它,这样会更简单。
内置的方法是使用numpy.genfromtxt
。根据你需要对文本文件进行的预处理量,它可能会满足你的需求,也可能不满足。不过,作为一个基本示例:(使用StringIO来模拟一个文件...)
from StringIO import StringIO
import numpy as np
txt_data = """
1\t2\t3
4\t\t6
7t\8t\9"""
infile = StringIO(txt_data)
data = np.genfromtxt(infile, usemask=True, delimiter='\t')
这段代码的输出是:
masked_array(data =
[[1.0 2.0 3.0]
[4.0 -- 6.0]
[7.0 8.0 9.0]],
mask =
[[False False False]
[False True False]
[False False False]],
fill_value = 1e+20)
有一点需要注意:如果你使用制表符作为分隔符,并且用空字符串来表示缺失值,那么在行的开头会出现缺失值的问题。(genfromtxt
实际上是调用 line.strip().split(delimiter)
)。如果可以的话,最好用像"xxx"
这样的标记来表示缺失值。