【问题标题】:Loading large arrays from file, numpy slower than list appending. Where is the bottle neck?从文件加载大型数组,numpy 比列表追加慢。瓶颈在哪里?
【发布时间】:2013-08-19 06:02:11
【问题描述】:

我有一个非常大的数据 .dat 文件,我正在加载到一个列表或 numpy 数组中。该文件包含值列,最后一列是该值应加载到数组中的次数的乘数。因此,在加载它时,需要运行第二个子循环以考虑到这一点。这样做是为了使总文件大小更小,因为在某些情况下它们会超过 1Gb。

我使用 numpy 预分配零数组与附加到简单列表进行了一些测试,发现附加更快。虽然,在许多帖子中,情况不应该如此。瓶颈在哪里?

    if True:
            startTime1 = time.clock()
            ## Numpy way to load up the data
            dataAry = np.zeros(TotalSamples)
            multiColAry = np.loadtxt(filename,skiprows=2,                           usecols=(columNum,lastColLoc))
            latestLoc = 0               
            for i in range(0,multiColAry.shape[0]):
                curData = multiColAry[i][0]
                timesBeenHere = int(multiColAry[i][2])
                for j in range(0,timesBeenHere):
                    dataAry[latestLoc] = curData                        
                    latestLoc+=1
            endTime1 = time.clock()
            totalTime = (endTime1-startTime1) # in seconds
            totalTimeString = timeString(totalTime)

        if True:
            #Old string parsing directly version
            startTime1 = time.clock()
            totalAccepted = 0
            f = open(filename,'r')
            dataAry = []
            line = 'asdf'
            while line!='':
                line = f.readline()
                if line!='':
                    dataLineCols = line.split()
                    dataValue = float(dataLineCols[columNum])
                    timesBeenHere = float(dataLineCols[-1])
                    for j in range(0,int(timesBeenHere)):
                        totalAccepted+=1
                        dataAry.append(dataValue)

            f.close()
            endTime1 = time.clock()
            totalTime = (endTime1-startTime1) # in seconds
            totalTimeString = timeString(totalTime)

感谢任何 cmets/建议。

【问题讨论】:

  • 您是否尝试过:dataAry[latestLoc:latestLoc+timesBeenHere] = curData 而不是一一分配元素?众所周知,numpy 数组在对每个元素进行操作时很慢。 (“列表附加”方法也可以做到这一点)。

标签: python arrays list numpy loading


【解决方案1】:

在分配一个大的零数组时,您需要清除大量内存,因此如果您使用 np.zeros 分配一个足够大的数组,它很可能会开始分页,并且肯定会单独在该调用中清除您的处理器缓存。使用 ndarray(shape=(TotalSamples)) 参数分配数组不会初始化它。

其次,第一个版本的代码会跟踪第二个版本动态丢弃的数据。输入文件显然是一个数字文本表,第一个实现读取列 0 和 2,而第二个实现读取列 columnNum 和 -1。这表明只要 multiColAry 存在,第一个版本就至少保留一个列,而第二个版本在移动到下一行时将其丢弃。您可以使用loadtxt(filename, usecols=(0,2)) 避免这种情况。

顺便说一句,你知道files are iterable 吗?您使用f.readline() 和空字符串测试的棘手组合可以替换为for line in f:(和strings are false when empty,因此您无需与空字符串进行比较)。

另外,在使用 numpy 时,最好不要在 Python 中编写像 for j in range(0,timesBeenHere): 这样的内部循环。可以使用dataAry[latestLoc:latestLoc+timesBeenHere].fill(curData)dataAry.append(multiEntries) 对其进行重组。创建 multiEntries 本身就是一个章节,有np.ones(timesBeenHere)*dataValue(传统但如果它不适合缓存,则成本很高)或np.linspace(dataValue,dataValue,timesBeenHere) 之类的可能性。另见ndarray.put()

...直到现在我才注意到第二个版本构建了一个列表,而不是一个数组。这让人想起以后如何使用数据的问题。现在,我假设它在看不见的代码中被转换为一个 numpy 数组。

最后,我猜这样的事情可能最方便:

dataAry = np.empty(TotalSamples)
i=0
for line in open(filename):
  words=line.split()
  repeats=int(words[2])
  value=float(words[0])
  np.copyto(dataAry[i:i+repeats],value)
  i+=repeats

肯定有某种方法可以使用 numpy 来计算索引,但我不知道像这样手动解析并使用 loadtxt 加载完整表(嗯,有趣的列)的成本更高。

【讨论】:

  • 非常感谢您。因为我有 numpy 1.6,所以我改用 dataAry[i:i+timesBeenHere]=dataValue。制作了两个版本的更新循环,一个带有 dataAry = [None]*TotalSamples,另一个带有 dataAry = np.empty(TotalSamples)。两者的速度相似,numpy 的速度通常要长约 5%。暂时,我会坚持第一个,非 numpy 的,因为它通常快几秒钟。是的,加载列表后,使用 np.sort() 将其转换为 numpy 数组,然后执行许多步骤,包括生成直方图。
  • 你解码一个 RLE 编码的向量,然后从中制作一个直方图?听起来相当迂回,因为直方图是 RLE 列表中数据的分箱,并且以这种形式对其进行排序也便宜得多。
  • 数据存储在 .dat 文件中,不确定这是否意味着它会导致 RLE 编码向量,因为我不知道是这样。我将它加载到内存中进行排序,以便我轻松计算直方图的中值和置信水平。目前加载大约需要 1 分钟,排序和查找置信水平大约需要 30 秒,绘图大约需要 8 秒。所以,如果有更快的方法来完成这一切,我很感兴趣。
  • RLE 是运行长度编码,这个问题是关于扩展的压缩类型。我不确定我头脑中的置信水平,但是直接从这种压缩中计算中位数和直方图比从扩展版本中更有效。只需处理更少的条目。
【解决方案2】:

我相信你可以用 numpy.repeat(multiColAry[:, 0], multiColAry[:, 2]) 替换你的 for 循环,这应该会有很大的不同。

另外,numpy 数组通常是索引array[i, j, k] 而不是array[i][j][k],在这种情况下结果应该是相同的,但在某些情况下,后者实际上会给你错误的结果。无论哪种情况,前者都应该更快。

最后,在使用 numpy 编程时,不鼓励使用元素操作和 for 循环。相反,鼓励使用数组或“矢量化”代码。在此范例中,您将程序表示为数组的操作,而不是对其元素的操作。 Numpy 针对这种编程进行了优化。我知道这对于从 C 或 Java 等低级语言转过来的人来说是陌生的,但它类似于 Matlab 或 IDL 等其他科学编程语言。

【讨论】:

  • 感谢 cmets。当我尝试增加对 numpy 的理解和能力时,我会牢记它们。我未来的博士工作将需要高效的代码,如果我最终用 Python 编写该软件,这些建议肯定会派上用场。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-24
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 2019-07-27
  • 2012-12-03
  • 2017-07-17
相关资源
最近更新 更多