【问题标题】:Pythonic way to populate numpy array填充 numpy 数组的 Pythonic 方法
【发布时间】:2011-09-09 00:40:12
【问题描述】:

我发现自己使用 csv 阅读器和 for 循环遍历每一行来解析大量数据文件(通常在 .csv 文件或类似文件中)。例如,数据通常是浮点数表。

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) 不会就地追加,因此需要为表中的每个点重新创建数组(这很慢且不必要)。我也可以遍历数据列列表,并在完成后将它们包装到一个数组中(这是我一直在做的),但有时对于 when 我已经完成了文件的解析,并且可能需要在后面的列表中添加一些内容。

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

(另一方面:这有点烦人,通常人们使用列来组织数据,但 csv 如果阅读器包含 read_column 参数(是的,我知道它不会非常高效),则按行读取,我认为很多人会避免使用上述样板代码来解析 csv 数据文件。)

【问题讨论】:

    标签: python arrays numpy


    【解决方案1】:

    numpy.loadtxt:

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

    Documentation.


    编辑:对于 numpy 数组的列表,

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

    【讨论】:

    • 我之前考虑过这个,但它有一些问题,特别是它要求行长度在数组中相同。尽管我的小 sn-p 假设相同,但它并不总是发生(例如空行表示数据收集爆发之间的中断)。
    【解决方案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))
    

    【讨论】:

    • “NumPy...根本不提供 .append() 方法” NumPy 确实有一个 append 方法。它或多或少像 python append 一样工作,只是它不是“到位”。
    • @doug: a = np.array(range(3)) 成功。然后,a.append(4) 给出消息AttributeError: 'numpy.ndarray' object has no attribute 'append'。如果 NumPy 数组有 .append() 方法,那么我在这里做错了什么?
    • 所以试试这个:a = NP.random.randint(0, 10, 5); a = NP.append(a, [2, 3])。所以 NumPy 有一个 append function 而不是 append 方法——这使得你在上面的答案中的陈述完全正确!
    • 我通常会在回答之前先尝试一下。我没想到要寻找非方法append() 函数!
    【解决方案3】:

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

    在这种情况下的优势:

    • 流式加载,

    • 预先指定结果数组的数据类型,并且

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

    第一个是固有的——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)
    

    如果您不想使用可迭代对象加载数据,您仍然可以使用 NumPy 函数 empty 为目标数组预分配内存,并且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])
    

    【讨论】:

      猜你喜欢
      • 2013-11-10
      • 2011-01-07
      • 1970-01-01
      • 2015-02-12
      • 2018-05-07
      • 1970-01-01
      • 2019-07-23
      • 2013-11-18
      • 1970-01-01
      相关资源
      最近更新 更多