【问题标题】:How do I search through a very large csv file?如何搜索非常大的 csv 文件?
【发布时间】:2016-12-22 22:42:00
【问题描述】:

我有 2 个 csv 文件(其中一个是 .tab),它们都有 2 列数字。我的工作是遍历第一个文件的每一行,看看它是否与第二个文件中的任何行匹配。如果是这样,我会在我的输出 csv 文件中打印一个空行。否则,我将 'R,R' 打印到输出 csv 文件。我当前的算法执行以下操作:

  1. 扫描第二个文件的每一行(每行两个整数),转到二维数组中这两个整数的位置(所以如果整数是 2 和 3,我将转到位置 [2,3])并赋值为 1。
  2. 遍历第一个文件的每一行,检查每一行的两个整数在数组中的位置是否为1,然后将相应的输出打印到第三个csv文件。

不幸的是 csv 文件非常大,所以我在运行时立即收到“MemoryError:”。扫描大型 csv 文件的替代方法是什么?

我正在使用 Jupyter Notebook。我的代码:

import csv
import numpy

def SNP():
    thelines = numpy.ndarray((6639,524525))
    tempint = 0
    tempint2 = 0
    with open("SL05_AO_RO.tab") as tsv:
        for line in csv.reader(tsv, dialect="excel-tab"):
            tempint = int(line[0])
            tempint2 = int(line[1])
            thelines[tempint,tempint2] = 1
    return thelines

def common_sites():
    tempint = 0
    tempint2 = 0
    temparray = SNP()
    print('Checkpoint.')
    with open('output_SL05.csv', 'w', newline='') as fp:
        with open("covbreadth_common_sites.csv") as tsv:
            for line in csv.reader(tsv, dialect="excel-tab"):
                tempint = int(line[0])
                tempint2 = int(line[1])
                if temparray[tempint,tempint2] == 1:
                    a = csv.writer(fp, delimiter=',')
                    data = [['','']]
                    a.writerows(data)
                else:
                    a = csv.writer(fp, delimiter=',')
                    data = [['R','R']]
                    a.writerows(data)
    print('Done.')
    return

common_sites()

文件: https://drive.google.com/file/d/0B5v-nJeoVouHUjlJelZtV01KWFU/view?usp=sharinghttps://drive.google.com/file/d/0B5v-nJeoVouHSDI4a2hQWEh3S3c/view?usp=sharing

【问题讨论】:

  • 问题可能是这样的:numpy.ndarray((6639,524525))。你不应该使用ndarray构造函数,你应该使用arrayzeros。但无论如何,您正在制作一个 6639*524525 的 np.float64 数组,这将至少需要 6639*524525*1e-9*(64/8) == 27.8585718 演出。但是查看您的文件,它们很小,您可能只需将它们都加载到内存中,从一个中创建一个集合,然后遍历另一个并检查该集合的成员资格。使用与您可以获得的可能数字大小相同的数组可能是实现这一目标的内存效率最低的方法。

标签: python csv


【解决方案1】:

您的数据集确实不是那么大,但它相对稀疏。您没有使用稀疏结构来存储导致问题的数据。
只需使用元组的set 来存储看到的数据,然后在该set 上查找O(1),例如:

In [1]:
  import csv
  with open("SL05_AO_RO.tab") as tsv:
      seen = set(map(tuple, csv.reader(tsv, dialect="excel-tab")))
  with open("covbreadth_common_sites.csv") as tsv:
      common = [line for line in csv.reader(tsv, dialect="excel-tab") if tuple(line) in seen]
  common[:10]
Out[1]:
  [['1049', '7280'], ['1073', '39198'], ['1073', '39218'], ['1073', '39224'], ['1073', '39233'],
   ['1098', '661'], ['1098', '841'], ['1103', '15100'], ['1103', '15107'], ['1103', '28210']]

10 loops, best of 3: 150 ms per loop

In [2]:
  len(common), len(seen)
Out[2]:
  (190, 138205)

【讨论】:

    【解决方案2】:

    我有 2 个 csv 文件(其中一个是 .tab),它们都有 2 列数字。我的工作是遍历第一个文件的每一行,看看它是否与第二个文件中的任何行匹配。如果是这样,我会在我的输出 csv 文件中打印一个空行。否则,我将 'R,R' 打印到输出 csv 文件。

    import numpy as np
    
    f1 = np.loadtxt('SL05_AO_RO.tab')
    f2 = np.loadtxt('covbreadth_common_sites.csv')
    
    f1.sort(axis=0)
    f2.sort(axis=0)
    
    i, j = 0, 0
    while i < f1.shape[0]:
        while j < f2.shape[0] and f1[i][0] > f2[j][0]:
            j += 1
        while j < f2.shape[0] and f1[i][0] == f2[j][0] and f1[i][1] > f2[j][1]:
            j += 1
        if j < f2.shape[0] and np.array_equal(f1[i], f2[j]):
            print()
        else:
            print('R,R')
        i += 1
    
    1. 将数据加载到ndarray 以优化内存使用率
    2. 对数据进行排序
    3. 在已排序的数组中查找匹配项

    总复杂度为O(n*log(n) + m*log(m)),其中 n 和 m 是输入文件的大小。

    使用set() 不会减少每个唯一条目的内存使用量,因此我不建议将它用于大型数据集。

    【讨论】:

      【解决方案3】:

      由于 CSV 只是一个数据库转储,请将其导入任何 SQL 数据库,然后对其进行查询。这是一种非常有效的方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-03-24
        • 1970-01-01
        • 2013-05-07
        • 2013-01-10
        • 1970-01-01
        • 1970-01-01
        • 2018-11-01
        相关资源
        最近更新 更多