我有一个格式为
的文件2,3: true
3,5: false
4,2: true
如何将true
的行转换为2D numpy数组
[[2,3],[4,2]]
我尝试了numpy.genfromtxt
,但是如何应用条件并将读取行限制为前两组数字?
答案 0 :(得分:3)
几百万行的整数可能不会太大而无法一次加载到NumPy阵列中(取决于计算机的可用RAM)。因此,您可以通过首先加载完整的数值数组,然后加载布尔掩码来生成所需的数组:
import numpy as np
data = np.genfromtxt('data', delimiter=',', usecols=[0,1], comments=':', dtype=int)
mask = np.genfromtxt('data', delimiter=' ', usecols=[1], dtype=str) == 'true'
result = data[mask]
产量
array([[2, 3],
[4, 2]])
我使用了两次调用np.genfromtxt
来解决数据文件有两个不同分隔符(即逗号和空格)的问题。
虽然加载整个数组可能看起来很浪费,但它比逐行解析文件要快得多(前提是你有足够的内存来执行此操作。)
事实证明 - thanks to hpaulj是为了激励我进行测试 - 简单的for-loop
要快得多:
例如,使用此设置:
import numpy as np
def make_data(N=10**6):
data = np.random.randint(10, size=(N, 2))
mask = np.array(['true', 'false'])[np.random.randint(2, size=N)]
with open('data', 'w') as f:
for row, maski in zip(data, mask):
f.write('{},{}: {}\n'.format(row[0], row[1], maski))
def using_genfromtxt():
data = np.genfromtxt('data', delimiter=',', usecols=[0,1], comments=':', dtype=int)
mask = np.genfromtxt('data', delimiter=' ', usecols=[1], dtype=str) == 'true'
result = data[mask]
return result
def using_readline():
"""
https://stackoverflow.com/a/50144016/190597 (hpaulj)
"""
def foo1(f):
for line in f:
x,y = line.split(':')
if y.strip()=='true':
yield x.split(',')
with open('data', 'r') as f:
return np.array(list(foo1(f)), dtype=int)
make_data()
我们可以使用IPython来衡量using_genfromtxt
与using_readline
的速度:
In [152]: %timeit using_genfromtxt()
1 loop, best of 3: 8.8 s per loop
In [171]: %timeit using_readline()
1 loop, best of 3: 861 ms per loop
所以一个简单的for-loop
实际上要快10倍。
答案 1 :(得分:2)
另一种处理混合分隔符和条件的方法是通过过滤函数传递文件。
定义一个生成器,它接受一个文件或任何在行上迭代的东西,并返回一组过滤的字符串:
def foo(f):
for line in f:
x,y = line.split(':')
if y.strip()=='true':
yield x
使用文本替换文件:
In [55]: txt='''2,3: true
...: 3,5: false
...: 4,2: true
...: 2,3: true
...: 3,5: false
...: 4,2: true'''
生成器返回字符串,如下所示:
In [56]: list(foo(txt.splitlines()))
Out[56]: ['2,3', '4,2', '2,3', '4,2']
genfromtxt
很容易将这样的Feed转换为数组:
In [57]: np.genfromtxt(foo(txt.splitlines()),delimiter=',', dtype=int)
Out[57]:
array([[2, 3],
[4, 2],
[2, 3],
[4, 2]])
genfromtxt
在Python中迭代一个文件,因此使用foo
不应该改变它的速度。
pandas
有一个很好的csv阅读器,但编译得更快的版本并没有像Python那样多的花里胡哨。
或者我可以完全跳过genfromtxt
:
def foo1(f):
for line in f:
x,y = line.split(':')
if y.strip()=='true':
yield x.split(',')
In [63]: np.array(list(foo1(txt.splitlines())), dtype=int)
Out[63]:
array([[2, 3],
[4, 2],
[2, 3],
[4, 2]])
选择行后,文件格式很简单,np.array
可以处理它,并直接执行字符串到整数转换。