我有以下形式的数据:
#---------------------
# 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']
我有两个问题:
为什么np.genfromtxt()在导入时不删除数据头?什么时候数据被导入数组B仍然具有标头p,q。。。y 3,y 4。
为什么我们必须为标题名称提供下划线,例如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
'。我看不出用参数来解决这个问题。
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
以外的东西。
这看起来像是最干净的加载-显式跳过前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