1

我希望使用 Python 尽可能快地完成以下操作:

  • 读取 csv 文件的 i 到 j 行
  • 在 csv[row=(loop i to j)][column=3] 中创建所有字符串的连接

我的第一个代码是以下循环(i to j)

with open('Train.csv', 'rt') as f:
    row = next(itertools.islice(csv.reader(f), row_number, row_number+1))
    tags = (row[3].decode('utf8'))
return tags

但是我上面的代码一次读取 csv 一列并且速度很慢。

如何在一次调用中读取所有行并快速连接?


编辑以获取更多信息:

csv 文件大小为 7GB;在 Windows XP 上,我只有 4GB 的 RAM;但我不需要阅读所有列(我认为只有 7GB 的 1% 会很好)。

4

4 回答 4

2

由于我知道您对哪些数据感兴趣,因此我可以从经验中讲:

import csv
with open('Train.csv', 'rt') as csvfile:
     reader = csv.reader(csvfile, delimiter=' ', quotechar='|')
     for row in reader:
         row[0]  # ID
         row[1]  # title
         row[2]  # body
         row[3]  # tags

您当然可以每行选择您想要的任何内容,然后随意存储。

通过使用迭代器变量,您可以决定要收集哪些行:

import csv
with open('Train.csv', 'rt') as csvfile:
     reader = csv.reader(csvfile, delimiter=' ', quotechar='|')
     linenum = 0
     tags = []      # you can preallocate memory to this list if you want though.
     for row in reader:
         if linenum > 1000 and linenum < 2000: 
            tags.append(row[3])    # tags
         if linenum == 2000:
            break   # so it won't read the next 3 million rows
         linenum += 1

它的好处还在于,当您逐行阅读时,这将真正使用低内存。

如前所述,如果您想要后面的情况,它仍然必须解析数据才能到达那里(这是不可避免的,因为 text 中有换行符,所以您不能跳到某一行)。就个人而言,我只是粗略地使用了 linux 的split, 将文件分成块,然后编辑它们以确保它们以 ID 开头(并以标签结尾)。

然后我用:

train = pandas.io.parsers.read_csv(file, quotechar="\"")

快速读取拆分文件。

于 2013-09-26T08:24:04.587 回答
1

您的问题没有包含足够的信息,可能是因为您没有看到一些现有的复杂性:大多数 CSV 文件每行包含一条记录。在这种情况下,跳过您不感兴趣的行很简单。但在 CSV 记录中可以跨行,因此一般解决方案(如标准库中的 CSV 阅读器)必须解析记录以跳过行。由您决定在您的用例中可以进行哪些优化。

下一个问题是,您不知道您发布的代码的哪一部分太慢了。测量它。您的代码运行速度永远不会超过从光盘读取文件所需的时间。你检查过吗?或者你猜到哪一部分要慢?

如果您想对适合内存的 CSV 数据进行快速转换,我建议使用/学习Pandas。因此,将代码分成两步可能是个好主意:

  1. 将文件缩减为所需的数据。
  2. 转换剩余的数据。
于 2013-09-26T08:27:26.063 回答
1

sed 专为“读取 csv 文件的 i 到 j 行”任务而设计。

如果解决方案不必是纯 Python,我认为用 sed 预处理 csv 文件sed -n 'i, jp',然后用 Python 解析输出会简单快捷。

于 2013-09-26T09:01:28.597 回答
1

如果文件不是很大(数百兆字节)并且您实际上需要读取很多行,那么可能只是

tags = " ".join(x.split("\t")[3]
                for x in open("Train.csv").readlines()[from_row:to_row+1])

将是最快的方式。

如果文件非常大,您唯一能做的就是遍历所有行,因为不幸的是 CSV 使用(通常)可变大小的记录。

如果偶然特定 CSV 使用固定大小的记录格式(对于大文件并不罕见),那么直接查找文件可能是一种选择。

如果文件使用可变大小的记录,并且必须使用不同的范围进行多次搜索,那么只创建一次简单的外部索引(例如,行->所有行号为 1000 的倍数的文件偏移量)可能是个好主意。

于 2013-09-26T08:06:36.993 回答