为什么 np.genfromtxt() 在 Python 中导入时不删除标头?



我有以下形式的数据:

#---------------------
# 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等。?为什么我们不能提供名称,因为它是y1,y2。。。y 4

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

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=1时,您必须说skip_header=4(3条注释行+1条标题行)。

因此,这种方法首先"抛出"评论行。然后,对于下一行,它提取标题。它将剩余的行与相关联的标头一起传递到np.genfromtxt函数中。

几个注意事项:

  • CCD_ 7+CCD_。因此,两者都使用的效果与两者都不使用的效果相同。所以两者都不用。

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

    B.dtype.names = [n.replace('_', ' ') for n in B.dtype.names]
    print B['y 1']  # [748 262 512 748 160 788 310 230]
    

您的格式正在与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'。我看不出用参数来解决这个问题。

commentsnames在您的情况下不合作。它可以跳过注释行,但随后会将名称行作为数据读取。

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以外的东西。

这看起来像是最干净的加载-显式跳过前3行,接受头行,然后使用jedwards's思想来替换_

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接受任何可迭代的输入,无论是文件、行列表还是类似的生成器。

值得一提的是,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

相关内容

  • 没有找到相关文章

最新更新