以高效的方式访问CSV文件中的特定记录 - Python

时间:2015-09-29 07:46:11

标签: python performance csv memory-efficient

我有一个巨大的csv文件,我正在使用Python CSV库的DictReader阅读它。它有序列号。和一些相关的信息。在我的应用程序中,我正在列出序列号。用户提供并检查CSV文件中是否存在这些内容。 第一次实施:

reader=csv.DictReader(open('sample.csv','rb'))
arr=[1000,7777,3434,2121,9999]
for row in reader:
    if row['Id'] in arr:
        print row['Title']

但这需要很长时间,因为我的csv文件包含超过100 000个条目

第二次实施:

reader=csv.DictReader(open('sample.csv','rb'))
arr=[1000,7777,3434,2121,9999]
arr.sort()
i=0
for row in reader:
    if row['Id']==arr[i]:
        print row['Title']
        i=i+1

但是这会产生模棱两可的结果,即有时它只打印标题为前两个或前三个序列no.s在arr

我想要一种更有效的方法,直接命中特定序列号,这可能吗?

请不要建议使用linecache或基于行的东西,因为我的标题分布在多行,所以基本上1 csv记录不等于文件中的1行。

4 个答案:

答案 0 :(得分:2)

您正在尝试阅读100,000行文本文件以查找极少数匹配项 在这些查找之前,我会认真考虑将csv文件预处理到sqlite3数据库中 我怀疑每次用户请求一些查找详细信息时都会提供csv文件,所以应该可以 当然,这取决于csv文件的更新频率,但我敢打赌它并不常见。将csv单个预处理到sqlite数据库中,用于多次查找将带来好处。

当你拥有的唯一工具是锤子时,一切看起来都像钉子一样!

编辑:要考虑的另一件事是,你认为你现在遇到问题,当csv文件变成2或3个Lakh大小时会发生什么。在某些时候,你将不得不咬紧牙关,要么以某种结构化格式交付csv文件,要么自己构建它。
还有csv文件包含的问题。目前你不能保证它没有重复,这可能会严重搞乱你的处理。如果将结构应用于数据,不仅会使搜索速度极快,而且还可以确保同时获得干净的数据。

编辑2:

这是一个很小的python脚本,用于创建一个包含2个Lakh记录的数据库 显然,在您的情况下,您将必须阅读csv文件并填充更多字段,但这个简单的测试在旧的64位PC上只需4.5秒。

1
11
111
12343
18475

如果您每100,000次事务只执行#!/usr/bin/python # -*- coding: utf-8 -*- import os,sqlite3 db_name = "2lakh.db" try: os.remove(db_name) except: pass db = sqlite3.connect(db_name) cursor = db.cursor() result = cursor.execute('CREATE TABLE if not exists Big (Big_id INTEGER NOT NULL PRIMARY KEY UNIQUE, Big_data CHAR)') cursor.execute('PRAGMA synchronous = 0') #Hands off data handling to OS n = 0 while n < 200001: try: db.execute("insert into Big (Big_id,Big_data) values (?,?)",(n,"This is some data")); except sqlite3.Error as e: print 'Big Insert Error '+str(e), 'Error' n += 1 # only report progress and commit database every 10000 records (speeds things up immensely) if (n % 10000) == 0: db.commit() print n, "records written" db.commit() db.close() ,则创建整个数据库的时间不到3秒。 我希望这会有所帮助。

答案 1 :(得分:0)

真实代码中的arr有多大?如果它比这大得多,那么使用它可能会付出代价。

arr={1000,7777,3434,2121,9999}

一个集合具有更快的包含检查,这似乎是这里的主要瓶颈。

答案 2 :(得分:0)

如果要多次访问csv文件,请阅读一次并将数据保存在随机访问的索引表单中,例如数据库。或者,如果要对其进行过滤以获取可用行的一小部分,则首先执行一次操作以丢弃所有特定垃圾并编写仅包含有用数据的新的较小csv文件。

如果您编写的代码从csv文件的这个实例中提取了所有您需要的内容,我认为您无法做很多事情来改进它。

至于它不能正常工作,你确定在找到arr [0](1000)之前你不想找arr [1](7777)吗?如果您希望所有行['Id']的行与arr中的任何内容匹配,无论顺序如何,您都需要测试row['Id'] in arr。另一个潜在的问题是csv在某些行上可能包含数字1000(或甚至999.999999999),在其他行上可能包含字符串“1000”(或“1000”等),与原始电子表格相匹配。 1000 != "1000""1000" != "1000 ",因此在比较相等值之前,可能需要进行一些仔细的数据按摩。

答案 3 :(得分:0)

从算法来讲,你的第一个实现是可行的方法,但如果它太慢,你有两到三个可能的优化。

  1. 使用set代替list

  2. 使用列表列表而不是词典列表,即不要使用csv.DictReeader,而是使用更简单的csv.reader

  3. 使用已编译的re来匹配您的目标,并针对已编译的re测试当前ID。

  4. 我写了两三个因为我不确定第三个是真正的优化,如果所有其他方法都失败了那么就不值得测试这最后的可能性了......但是...... 顺便说一句,什么是拉赫?