无法将制表符分隔的文件读入numpy 2-D数组

7

我是一个新手,正在尝试使用以下代码将制表符(\t)分隔的文本文件读入numpy数组矩阵:

train_data = np.genfromtxt('training.txt', dtype=None, delimiter='\t')

文件内容:

38   Private    215646   HS-grad    9    Divorced    Handlers-cleaners   Not-in-family   White   Male   0   0   40   United-States   <=50K
53   Private    234721   11th   7    Married-civ-spouse  Handlers-cleaners   Husband     Black   Male   0   0   40   United-States   <=50K
30   State-gov  141297   Bachelors  13   Married-civ-spouse  Prof-specialty  Husband     Asian-Pac-Islander  Male   0   0   40   India   >50K

我希望得到一个形状为(3, 15)的二维数组矩阵。
但是我的代码只返回了一个形状为(3,)的单行数组。
我不确定为什么每一行的十五个字段没有被分配到各自的列中。
我也尝试使用numpy的loadtxt(),但它无法处理数据类型转换,即使我给出了dtype=None,它仍然试图将字符串转换为默认的浮点类型并失败了。
尝试的代码如下:
train_data = np.loadtxt('try.txt', dtype=None, delimiter='\t')

Error:
ValueError: could not convert string to float: State-gov

任何建议吗?
谢谢

你尝试过像“dtype=String”这样的语句吗? - abiessu
哦,我可以使用更传统的文件读取方式(使用 CSV 读取器)来解决这个问题。 - Abhi
感谢@abiessu。dtype=np.str可以正常工作,但我不想将它们全部转换为字符串。因此,我依赖于dtype=None来自动为我进行类型转换,在处理数字时,它会优先考虑'int'或'float',而不是字符串。 - Abhi
3个回答

4
实际上,这里的问题是如果dtype是结构化的(即具有多个类型),np.genfromtxtnp.loadtxt都会返回一个结构化数组。您的数组报告其形状为(3,),因为从技术上讲它是一个'记录'的一维数组。这些'记录'保存了所有列,但您可以像访问二维数据一样访问所有数据。
您正在正确加载它:
In [82]: d = np.genfromtxt('tmp',dtype=None)

正如您报告的那样,它具有1d形状:
In [83]: d.shape
Out[83]: (3,)

但是你的所有数据都在那里:
In [84]: d
Out[84]: 
array([ (38, 'Private', 215646, 'HS-grad', 9, 'Divorced', 'Handlers-cleaners', 'Not-in-family', 'White', 'Male', 0, 0, 40, 'United-States', '<=50K'),
       (53, 'Private', 234721, '11th', 7, 'Married-civ-spouse', 'Handlers-cleaners', 'Husband', 'Black', 'Male', 0, 0, 40, 'United-States', '<=50K'),
       (30, 'State-gov', 141297, 'Bachelors', 13, 'Married-civ-spouse', 'Prof-specialty', 'Husband', 'Asian-Pac-Islander', 'Male', 0, 0, 40, 'India', '>50K')], 
      dtype=[('f0', '<i8'), ('f1', 'S9'), ('f2', '<i8'), ('f3', 'S9'), ('f4', '<i8'), ('f5', 'S18'), ('f6', 'S17'), ('f7', 'S13'), ('f8', 'S18'), ('f9', 'S4'), ('f10', '<i8'), ('f11', '<i8'), ('f12', '<i8'), ('f13', 'S13'), ('f14', 'S5')])

数组的 dtype 结构如下:
In [85]: d.dtype
Out[85]: dtype([('f0', '<i8'), ('f1', 'S9'), ('f2', '<i8'), ('f3', 'S9'), ('f4', '<i8'), ('f5', 'S18'), ('f6', 'S17'), ('f7', 'S13'), ('f8', 'S18'), ('f9', 'S4'), ('f10', '<i8'), ('f11', '<i8'), ('f12', '<i8'), ('f13', 'S13'), ('f14', 'S5')])

您仍然可以使用dtype中给定的名称访问“列”(也称为字段):

In [86]: d['f0']
Out[86]: array([38, 53, 30])

In [87]: d['f1']
Out[87]: 
array(['Private', 'Private', 'State-gov'], 
      dtype='|S9')

更加方便的做法是为字段命名:
In [104]: names = "age,military,id,edu,a,marital,job,fam,ethnicity,gender,b,c,d,country,income"

In [105]: d = np.genfromtxt('tmp',dtype=None, names=names)

现在您可以访问'age'字段等:

In [106]: d['age']
Out[106]: array([38, 53, 30])

In [107]: d['income']
Out[107]: 
array(['<=50K', '<=50K', '>50K'], 
      dtype='|S5')

或者35岁以下人群的收入

In [108]: d[d['age'] < 35]['income']
Out[108]: 
array(['>50K'], 
      dtype='|S5')

并超过35

In [109]: d[d['age'] > 35]['income']
Out[109]: 
array(['<=50K', '<=50K'], 
      dtype='|S5')

2

更新的答案

抱歉,我误读了您最初的问题:

我期望得到一个形状为(3,15)的二维数组矩阵

但是用我上面的代码只得到了一个形状为(3,)的单行数组

我认为您误解了 np.genfromtxt() 的返回值。在这种情况下,它将尝试推断文本文件中每个“列”的类型,并给您返回一个结构化/“记录”数组。每一行都包含多个字段(f0...f14),每个字段可以包含与文本文件中的“列”对应的不同类型的值。您可以通过名称索引特定字段,例如 data['f0']

您根本无法拥有一个异构类型的 (3,15) numpy 数组。例如,您可以拥有一个由字符串组成的 (3,15) 同类型数组:

>>> string_data = np.genfromtext('test', dtype=str, delimiter='\t')
>>> print string_data.shape
(3, 15)

当然,你可以像@DrRobotNinja的答案所示手动将列转换为任何类型。但是最好让numpy为您创建结构化数组,然后按字段索引并将列分配到新数组中。


1
我不相信Numpy数组可以在单个数组中处理不同的数据类型。可做的是将整个数组加载为字符串,然后根据需要将必要的列转换为数字。
# Load data as strings
train_data = np.loadtxt('try.txt', dtype=np.str, delimiter='\t')

# Convert numeric strings into integers
first_col = train_data[:,0].astype(np.int)
third_col = train_data[:,2].astype(np.int)

实际上,NumPy数组可以具有结构化数据类型(dtype),请参见我的回答。 - askewchan
@askewchan 问题在于,numpy似乎无法处理不同的字段类型来构建二维数组,因此DrRobotNinja的答案非常有帮助。 - ngeek
@ngeek,我鼓励你学习一下numpy如何处理单个数组中的不同字段类型,而不是试图通过将所有数字转换为字符串来超越它。这非常有用!请参见此处的其他两个答案。 - askewchan

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