Python 使用 Numpy 导入文本数组
Python Import Text Array with Numpy
我有一个如下所示的文本文件:
...
5 [0, 1] [512, 479] 991
10 [1, 0] [706, 280] 986
15 [1, 0] [807, 175] 982
20 [1, 0] [895, 92] 987
...
每一列都是用制表符分隔的,但有些列中有数组。我可以用 np.genfromtxt
以某种方式导入这些吗?
生成的解压缩列表应该是,例如:
data1 = [..., 5, 10, 15, 20, ...]
data2 = [..., [512, 479], [706, 280], ... ] (i.e. a 2D list)
etc.
我试过了
data1, data2, data3, data4 = np.genfromtxt('data.txt', dtype=None, delimiter='\t', unpack=True)
但是 data2
和 data3
是包含 'nan'.
的列表
无论您怎么看,csv
文件中的括号都是笨拙的。默认的 csv
结构是 2d - 行和统一列。括号增加了一层嵌套。但事实上,列是用制表符分隔的,而嵌套块是用逗号分隔的,这使得它更容易一些。
您的评论代码是(添加了换行符)
datastr = data[i][1][1:-1].split(',')
dataarray = []
for j in range(0, len(datastr)):
dataarray.append(int(datastr[j]))
data2.append(dataarray)
我假设 data[i]
看起来像(在标签拆分之后):
['5', '[0, 1]', '[512, 479]', '991']
因此,对于“[0,1]”,您可以剥离 []
,拆分其余部分,然后将该列表放回 data2
。
这看起来确实是一个可行的方法。 genfromtxt
确实处理括号或引号。 csv
reader 可以处理引用的文本,并且可能适合将 []
视为引号。但除此之外,我认为 '[]` 必须像您一样通过某种字符串处理来处理。
请记住,genfromtxt
只是读取行、解析它们,并将生成的列表收集到主列表中。然后它在最后将该列表转换为数组。所以自己逐行逐行解析,丝毫不逊色
=============
将您的示例作为文本文件:
In [173]: txt=b"""
...: 5 \t [0, 1] \t [512, 479] \t 991
...: 10 \t [1, 0] \t [706, 280] \t 986
...: 15 \t [1, 0] \t [807, 175] \t 982
...: 20 \t [1, 0] \t [895, 92] \t 987"""
一个简单的 genfromtxt
调用 dtype=None
:
In [186]: data = np.genfromtxt(txt.splitlines(), dtype=None, delimiter='\t', autostrip=True)
结果是一个包含整数和字符串字段的结构化数组:
In [187]: data
Out[187]:
array([(5, b'[0, 1]', b'[512, 479]', 991),
(10, b'[1, 0]', b'[706, 280]', 986),
(15, b'[1, 0]', b'[807, 175]', 982),
(20, b'[1, 0]', b'[895, 92]', 987)],
dtype=[('f0', '<i4'), ('f1', 'S6'), ('f2', 'S10'), ('f3', '<i4')])
字段按名称访问
In [188]: data['f0']
Out[188]: array([ 5, 10, 15, 20])
In [189]: data['f1']
Out[189]:
array([b'[0, 1]', b'[1, 0]', b'[1, 0]', b'[1, 0]'],
dtype='|S6')
如果我们可以处理 []
,您的数据可以很好地表示为具有复合 dtype
的结构化数组
In [191]: dt=np.dtype('i,2i,2i,i')
In [192]: np.ones((3,),dtype=dt)
Out[192]:
array([(1, [1, 1], [1, 1], 1), (1, [1, 1], [1, 1], 1),
(1, [1, 1], [1, 1], 1)],
dtype=[('f0', '<i4'), ('f1', '<i4', (2,)), ('f2', '<i4', (2,)), ('f3', '<i4')])
其中 'f1' 字段是 (3,2) 数组。
一种方法是通过过滤掉多余字符的函数传递 text/file。 genfromtxt
适用于任何可以一次输入一行的内容。
def afilter(txt):
for line in txt.splitlines():
line=line.replace(b'[', b' ').replace(b']', b'').replace(b',' ,b'\t')
yield line
此生成器删除了 [] 并将 , 替换为制表符,实际上生成了平面 csv 文件
In [205]: list(afilter(txt))
Out[205]:
[b'',
b'5 \t 0\t 1 \t 512\t 479 \t 991',
b'10 \t 1\t 0 \t 706\t 280 \t 986',
b'15 \t 1\t 0 \t 807\t 175 \t 982',
b'20 \t 1\t 0 \t 895\t 92 \t 987']
genfromtxt
和 dtype=None
将生成一个包含 6 列的数组。
In [209]: data=np.genfromtxt(afilter(txt),delimiter='\t',dtype=None)
In [210]: data
Out[210]:
array([[ 5, 0, 1, 512, 479, 991],
[ 10, 1, 0, 706, 280, 986],
[ 15, 1, 0, 807, 175, 982],
[ 20, 1, 0, 895, 92, 987]])
In [211]: data.shape
Out[211]: (4, 6)
但是如果我给它我上面定义的 dt
dtype,我会得到一个结构化数组:
In [206]: data=np.genfromtxt(afilter(txt),delimiter='\t',dtype=dt)
In [207]: data
Out[207]:
array([(5, [0, 1], [512, 479], 991), (10, [1, 0], [706, 280], 986),
(15, [1, 0], [807, 175], 982), (20, [1, 0], [895, 92], 987)],
dtype=[('f0', '<i4'), ('f1', '<i4', (2,)), ('f2', '<i4', (2,)), ('f3', '<i4')])
In [208]: data['f1']
Out[208]:
array([[0, 1],
[1, 0],
[1, 0],
[1, 0]], dtype=int32)
括号可以分几个层次来处理。我不认为其中一个比另一个有很多优势。
给定数据的潜在方法,但不使用 numpy:
import ast
data1, data2, data3, data4 = [],[],[],[]
for l in open('data.txt'):
data = l.split('\t')
data1.append(int(data[0]))
data2.append(ast.literal_eval(data[1]))
data3.append(ast.literal_eval(data[2]))
data4.append(int(data[3]))
print 'data1', data1
print 'data2', data2
print 'data3', data3
print 'data4', data4
给予
"data1 [5, 10, 15, 20]"
"data2 [[0, 1], [1, 0], [1, 0], [1, 0]]"
"data3 [[512, 479], [706, 280], [807, 175], [895, 92]]"
"data4 [991, 986, 982, 987]"
作为 genfromtxt
的替代方案,您可以尝试 fromregex
。您基本上在正则表达式组和 numpy 结构化数据类型的字段之间建立了类比。
在这个例子中,我解析了所有数字,而不用担心它们是单个数字还是数组。然后我切换到指定哪些列具有数组的数据类型。
import numpy as np
# regular expression that will extract 6 numbers from each line
re = 6 * r"(\d+)\D*"
# dtype for a single number
dt_num = np.int
# structured dtype of 6 numbers
dt = 6 * [('', dt_num)]
# parse the file
a = np.fromregex("data.txt", re, dt)
# change to a more descriptive structured dtype
a.dtype = [
('data1', dt_num),
('data2', dt_num, (2,)),
('data3', dt_num, (2,)),
('data4', dt_num)
]
print(a['data1'])
print(a['data2'])
print(a['data3'])
print(a['data4'])
切换 numpy 数组的 dtype 的好处是它不必处理或制作数据的新副本,它只是重新解释您访问数据时获得的内容。
此解决方案的缺点之一是构建复杂的正则表达式和构建结构化数据类型可能会变得很丑陋。在这种情况下,您必须使两者保持同步。
我有一个如下所示的文本文件:
...
5 [0, 1] [512, 479] 991
10 [1, 0] [706, 280] 986
15 [1, 0] [807, 175] 982
20 [1, 0] [895, 92] 987
...
每一列都是用制表符分隔的,但有些列中有数组。我可以用 np.genfromtxt
以某种方式导入这些吗?
生成的解压缩列表应该是,例如:
data1 = [..., 5, 10, 15, 20, ...]
data2 = [..., [512, 479], [706, 280], ... ] (i.e. a 2D list)
etc.
我试过了
data1, data2, data3, data4 = np.genfromtxt('data.txt', dtype=None, delimiter='\t', unpack=True)
但是 data2
和 data3
是包含 'nan'.
无论您怎么看,csv
文件中的括号都是笨拙的。默认的 csv
结构是 2d - 行和统一列。括号增加了一层嵌套。但事实上,列是用制表符分隔的,而嵌套块是用逗号分隔的,这使得它更容易一些。
您的评论代码是(添加了换行符)
datastr = data[i][1][1:-1].split(',')
dataarray = []
for j in range(0, len(datastr)):
dataarray.append(int(datastr[j]))
data2.append(dataarray)
我假设 data[i]
看起来像(在标签拆分之后):
['5', '[0, 1]', '[512, 479]', '991']
因此,对于“[0,1]”,您可以剥离 []
,拆分其余部分,然后将该列表放回 data2
。
这看起来确实是一个可行的方法。 genfromtxt
确实处理括号或引号。 csv
reader 可以处理引用的文本,并且可能适合将 []
视为引号。但除此之外,我认为 '[]` 必须像您一样通过某种字符串处理来处理。
请记住,genfromtxt
只是读取行、解析它们,并将生成的列表收集到主列表中。然后它在最后将该列表转换为数组。所以自己逐行逐行解析,丝毫不逊色
=============
将您的示例作为文本文件:
In [173]: txt=b"""
...: 5 \t [0, 1] \t [512, 479] \t 991
...: 10 \t [1, 0] \t [706, 280] \t 986
...: 15 \t [1, 0] \t [807, 175] \t 982
...: 20 \t [1, 0] \t [895, 92] \t 987"""
一个简单的 genfromtxt
调用 dtype=None
:
In [186]: data = np.genfromtxt(txt.splitlines(), dtype=None, delimiter='\t', autostrip=True)
结果是一个包含整数和字符串字段的结构化数组:
In [187]: data
Out[187]:
array([(5, b'[0, 1]', b'[512, 479]', 991),
(10, b'[1, 0]', b'[706, 280]', 986),
(15, b'[1, 0]', b'[807, 175]', 982),
(20, b'[1, 0]', b'[895, 92]', 987)],
dtype=[('f0', '<i4'), ('f1', 'S6'), ('f2', 'S10'), ('f3', '<i4')])
字段按名称访问
In [188]: data['f0']
Out[188]: array([ 5, 10, 15, 20])
In [189]: data['f1']
Out[189]:
array([b'[0, 1]', b'[1, 0]', b'[1, 0]', b'[1, 0]'],
dtype='|S6')
如果我们可以处理 []
,您的数据可以很好地表示为具有复合 dtype
In [191]: dt=np.dtype('i,2i,2i,i')
In [192]: np.ones((3,),dtype=dt)
Out[192]:
array([(1, [1, 1], [1, 1], 1), (1, [1, 1], [1, 1], 1),
(1, [1, 1], [1, 1], 1)],
dtype=[('f0', '<i4'), ('f1', '<i4', (2,)), ('f2', '<i4', (2,)), ('f3', '<i4')])
其中 'f1' 字段是 (3,2) 数组。
一种方法是通过过滤掉多余字符的函数传递 text/file。 genfromtxt
适用于任何可以一次输入一行的内容。
def afilter(txt):
for line in txt.splitlines():
line=line.replace(b'[', b' ').replace(b']', b'').replace(b',' ,b'\t')
yield line
此生成器删除了 [] 并将 , 替换为制表符,实际上生成了平面 csv 文件
In [205]: list(afilter(txt))
Out[205]:
[b'',
b'5 \t 0\t 1 \t 512\t 479 \t 991',
b'10 \t 1\t 0 \t 706\t 280 \t 986',
b'15 \t 1\t 0 \t 807\t 175 \t 982',
b'20 \t 1\t 0 \t 895\t 92 \t 987']
genfromtxt
和 dtype=None
将生成一个包含 6 列的数组。
In [209]: data=np.genfromtxt(afilter(txt),delimiter='\t',dtype=None)
In [210]: data
Out[210]:
array([[ 5, 0, 1, 512, 479, 991],
[ 10, 1, 0, 706, 280, 986],
[ 15, 1, 0, 807, 175, 982],
[ 20, 1, 0, 895, 92, 987]])
In [211]: data.shape
Out[211]: (4, 6)
但是如果我给它我上面定义的 dt
dtype,我会得到一个结构化数组:
In [206]: data=np.genfromtxt(afilter(txt),delimiter='\t',dtype=dt)
In [207]: data
Out[207]:
array([(5, [0, 1], [512, 479], 991), (10, [1, 0], [706, 280], 986),
(15, [1, 0], [807, 175], 982), (20, [1, 0], [895, 92], 987)],
dtype=[('f0', '<i4'), ('f1', '<i4', (2,)), ('f2', '<i4', (2,)), ('f3', '<i4')])
In [208]: data['f1']
Out[208]:
array([[0, 1],
[1, 0],
[1, 0],
[1, 0]], dtype=int32)
括号可以分几个层次来处理。我不认为其中一个比另一个有很多优势。
给定数据的潜在方法,但不使用 numpy:
import ast
data1, data2, data3, data4 = [],[],[],[]
for l in open('data.txt'):
data = l.split('\t')
data1.append(int(data[0]))
data2.append(ast.literal_eval(data[1]))
data3.append(ast.literal_eval(data[2]))
data4.append(int(data[3]))
print 'data1', data1
print 'data2', data2
print 'data3', data3
print 'data4', data4
给予
"data1 [5, 10, 15, 20]"
"data2 [[0, 1], [1, 0], [1, 0], [1, 0]]"
"data3 [[512, 479], [706, 280], [807, 175], [895, 92]]"
"data4 [991, 986, 982, 987]"
作为 genfromtxt
的替代方案,您可以尝试 fromregex
。您基本上在正则表达式组和 numpy 结构化数据类型的字段之间建立了类比。
在这个例子中,我解析了所有数字,而不用担心它们是单个数字还是数组。然后我切换到指定哪些列具有数组的数据类型。
import numpy as np
# regular expression that will extract 6 numbers from each line
re = 6 * r"(\d+)\D*"
# dtype for a single number
dt_num = np.int
# structured dtype of 6 numbers
dt = 6 * [('', dt_num)]
# parse the file
a = np.fromregex("data.txt", re, dt)
# change to a more descriptive structured dtype
a.dtype = [
('data1', dt_num),
('data2', dt_num, (2,)),
('data3', dt_num, (2,)),
('data4', dt_num)
]
print(a['data1'])
print(a['data2'])
print(a['data3'])
print(a['data4'])
切换 numpy 数组的 dtype 的好处是它不必处理或制作数据的新副本,它只是重新解释您访问数据时获得的内容。
此解决方案的缺点之一是构建复杂的正则表达式和构建结构化数据类型可能会变得很丑陋。在这种情况下,您必须使两者保持同步。