1

我有以下形式的数据:

#---------------------
# Data
#---------------------
p   q   r   y 1 y 2 y 3 y 4
2   8   14  748 748 748 790
2   9   22  262 245 252 328
1   5   19  512 514 511 569
2   7   19  748 748 748 805
3   11  13  160 168 108 164
2   7   20  788 788 788 848
1   4   15  310 310 310 355
3   12  17  230 210 213 218

我正在尝试使用 np.genfromtxt() 生成数组 B,使用以下代码:

import numpy as np
A = open('data.dat', "r")
line = A.readline()
while line.startswith('#'):
    line = A.readline()
A_header = line.split("\t")
A_header[-1] = A_header[-1].strip()
B = np.genfromtxt('data.dat', comments='#', delimiter='\t', names = A_header, dtype = None, unpack = True).transpose()
print B
print B['y_1']

我有两个问题:

  1. 为什么 np.genfromtxt() 在导入时不删除数据头?导入数据时,数组 B 仍然具有标题 p, q, ... y 3, y 4。

  2. 为什么我们必须为标题名称提供下划线,例如 y_1、y_2 等?为什么我们不能提供 y 1, y 2 ... y 4 的名称?

4

3 回答 3

3

与其打开文件两次,不如说:

import numpy as np

with open('input.txt', "r") as data:
    while True:
        line = data.readline()
        if not line.startswith('#'): break

    header = [e for e in line.strip().split('\t') if e]
    print(header)

    B = np.genfromtxt(data, names=header, dtype=None, delimiter='\t')

print B
print B['y_1']

输出:

# header
['p', 'q', 'r', 'y 1', 'y 2', 'y 3', 'y 4']

# B
[(2, 8, 14, 748, 748, 748, 790) (2, 9, 22, 262, 245, 252, 328)
 (1, 5, 19, 512, 514, 511, 569) (2, 7, 19, 748, 748, 748, 805)
 (3, 11, 13, 160, 168, 108, 164) (2, 7, 20, 788, 788, 788, 848)
 (1, 4, 15, 310, 310, 310, 355) (3, 12, 17, 230, 210, 213, 218)]

# B['y_1']
[748 262 512 748 160 788 310 230]

np.genfromtxt在这里,您不是将文件名传递给 ,而是传递data文件阅读器生成器。

skip_header否则,您会陷入一种无法正常工作的奇怪情况,因为它会考虑注释行。因此,skip_header=4当 make 是skip_header=1.

所以这种方法首先“抛出”注释行。然后对于下一行,它提取标题。np.genfromtxt它将剩余的行与相关的标题一起传递到函数中。

几点注意事项:

  • unpack=True+transpose()相互抵消。所以两者都用的效果和都不用是一样的。所以两者都不用。

  • 如果您真的想使用带空格(而不是下划线)的名称访问字段,您始终可以在生成以下内容后重命名字段ndarray

    B.dtype.names = [n.replace('_', ' ') for n in B.dtype.names]
    print B['y 1']  # [748 262 512 748 160 788 310 230]
    
于 2015-04-04T20:55:16.780 回答
1

您的格式正在与一些正在做出的假设作斗争genfromtxt

1)你有注释行和标题行(没有#字符)

2)您的列名有空格,它genfromtxt坚持转换为_(或其他一些有效字符)。

如果我从您的示例创建一个文本文件,并用制表符替换空白(这很痛苦,特别是因为我的编辑器设置为用空格替换制表符),这有效:

In [330]: np.genfromtxt('stack29451030.txt',delimiter='\t',dtype=None,skip_header=3,names=True)
Out[330]: 
array([(2, 8, 14, 748, 748, 748, 790), (2, 9, 22, 262, 245, 252, 328)], 
      dtype=[('p', '<i4'), ('q', '<i4'), ('r', '<i4'), ('y_1', '<i4'), ('y_2', '<i4'), ('y_3', '<i4'), ('y_4', '<i4')])

我玩过replace_space=' '。看起来它只使用产生有效 Python 变量和属性名称的替换。所以'y_1'很好,但不是'y 1'。我看不到使用参数的方法。

comments并且names不要在你的情况下合作。它可以跳过注释行,但随后会将名称行作为数据读取。

In [350]: np.genfromtxt('stack29451030.txt',delimiter='\t',dtype=None,comments='#')
Out[350]: 
array([['p', 'q', 'r', 'y 1', 'y 2', 'y 3', 'y 4'],
       ['2', '8', '14', '748', '748', '748', '790'],
       ['2', '9', '22', '262', '245', '252', '328']], 
      dtype='|S3')

它可以处理名称行#p q r y1 y2 y3 y4,例如忽略 #,但它不会跳过前面的注释行。因此,如果您可以删除注释行或标题行,它可以读取它。但是两者看起来你必须使用除comments.

这看起来像最干净的加载 - 明确跳过第 1 3 行,接受标题行,然后使用jedwards'sidea 替换_.

In [396]: A=np.genfromtxt('stack29451030.txt',delimiter='\t',dtype=None,skip_header=3,names=True)

In [397]: A.dtype.names = [n.replace('_', ' ') for n in A.dtype.names]

In [398]: A
Out[398]: 
array([(2, 8, 14, 748, 748, 748, 790), (2, 9, 22, 262, 245, 252, 328)], 
      dtype=[('p', '<i4'), ('q', '<i4'), ('r', '<i4'), ('y 1', '<i4'), ('y 2', '<i4'), ('y 3', '<i4'), ('y 4', '<i4')])

如果你不知道有多少注释行,这个生成器可以过滤掉它们:

with open('stack29451030.txt') as f:
    g = (line for line in f if not line.startswith('#'))
    A = np.genfromtxt(g, delimiter='\t', names=True, dtype=None)

genfromtxt接受来自任何可迭代对象的输入,无论是文件、行列表还是像这样的生成器。

于 2015-04-07T03:52:41.337 回答
0

对于它的价值,请pandas.read_table轻松阅读此文件。

import pandas
B = pandas.read_table('data.dat', comment='#')

print B['y 1']  # Note the space is retained in the column name
于 2015-04-07T05:05:55.167 回答