从文本字段创建掩码数组

2 投票
1 回答
1615 浏览
提问于 2025-04-16 04:01

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"这样的标记来表示缺失值。

撰写回答