Pythonic方式填充numpy数组

时间:2011-09-09 00:40:13

标签: python arrays numpy

我发现自己使用csv阅读器解析了大量数据文件(通常是.csv文件或类似文件),并使用for循环迭代每一行。例如,数据通常是一个浮动表。

reader = csv.reader(open('somefile.csv'))
header = reader.next()

res_list = [list() for i in header]    

for line in reader:
  for i in range(len(line)):
    res_list[i].append(float(line[i]))

result_dict = dict(zip(header,res_list)) #so we can refer by column title

这是一个填充的好方法,所以我将每个列作为一个单独的列表,但是,我更希望项目列表(和嵌套列表)的默认数据容器是numpy数组,因为99次超过100个数字得到泵入各种处理脚本/功能,并具有numpy列表的力量使我的生活更轻松。

numpy append(arr, item)不会就地附加,因此需要为表中的每个点重新创建数组(这是缓慢且不必要的)。我也可以遍历数据列列表并在完成之后将它们包装成一个数组(这就是我一直在做的事情),但有时它不是那么明确地切割我已经完成了对文件的解析,并且可能需要稍后将内容添加到列表中。

我想知道是否有一些不那么乏味的方法(使用过度使用的短语“pythonic”)以类似的方式处理数据表,或者动态填充数组(底层容器是列表)并且不会一直复制数组。

(另一个注意事项:通常人们使用列来组织数据,但是如果读者合并了read_column参数,那么csv会读入行(是的,我知道它不会超级高效) ,我想很多人都会避免像上面这样的锅炉板代码来解析csv数据文件。)

3 个答案:

答案 0 :(得分:7)

numpy.loadtxt

X = numpy.loadtxt('somefile.csv', delimiter=',')

Documentation.


编辑:获取numpy数组列表

X = [scipy.array(line.split(','), dtype='float') 
     for line in open('somefile.csv', 'r')]

答案 1 :(得分:2)

我认为很难改善你所拥有的东西。 Python列表构建和追加相对便宜; NumPy数组的创建成本更高,并且根本不提供.append()方法。因此,最好的办法是按照您现在的方式构建列表,然后在时机成文时强制转移到np.array()

一些小问题:

  • 使用[]创建列表比调用list()稍快一些。这是程序运行时的一小部分,您可以随意忽略这一点。

  • 如果您实际上没有使用循环索引,则可以使用_作为变量名来记录此内容。

  • 迭代序列通常比找到序列的长度更好,构建一个range(),然后对序列进行大量索引。如果您还需要索引,可以使用enumerate()获取索引。

将它们放在一起,我认为这是一个稍微改进的版本。但它与你的原版几乎没有变化,我想不出任何真正好的改进。

reader = csv.reader(open('somefile.csv'))
header = reader.next()

res_list = [ [] for _ in header]

for row in reader:
    for i, val in enumerate(row):
        res_list[i].append(float(val))

# build dict so we can refer by column title
result_dict = dict((n, res_list[i]) for i, n in enumerate(header))

答案 2 :(得分:2)

为了有效地将数据加载到 NumPy 数组,我喜欢NumPy的 fromiter 功能。

在这方面的优势:

  • 流式加载

  • 预先指定reesult数组的数据类型

  • 预先分配输出数组,然后填充 来自可迭代的流。

第一个是固有的 - fromiter 只接受以可迭代形式输入的数据 - 后两个通过传递给fromiter的第二个和第三个参数进行管理, dtype,计数

>>> import numpy as NP
>>> # create some data to load:
>>> import random
>>> source_iterable = (random.choice(range(100)) for c in range(20))

>>> target = NP.fromiter(source_iterable, dtype=NP.int8, count=v.size)
>>> target
      array([85, 28, 37,  4, 23,  5, 47, 17, 78, 40, 28,  5, 69, 47, 15, 92, 
             41, 33, 33, 98], dtype=int8)

如果您不想使用iterable加载数据,您仍然可以使用NumPy函数清空 为目标数组预分配内存,并且的 empty_like

>>> source_vec = NP.random.rand(10)
>>> target = NP.empty_like(source_vec)
>>> target[:] = source_vec
>>> target
  array([ 0.5472,  0.5085,  0.0803,  0.4757,  0.4831,  0.3054,  0.1024,  
          0.9073,  0.6863,  0.3575])

或者,你可以通过调用 empty 创建一个空的(预分配的)数组,然后只传入你想要的形状。与 empty_like 相比,此功能让您传递数据类型:

>>> target = NP.empty(shape=s.shape, dtype=NP.float)
>>> target
  array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.])
>>> target[:] = source
>>> target
  array([ 0.5472,  0.5085,  0.0803,  0.4757,  0.4831,  0.3054,  0.1024,  
          0.9073,  0.6863,  0.3575])