如何读取大型 csv 文件的特定行
How to read specific lines of a large csv file
我正在尝试读取大型 csv 文件的某些特定行,但我不想将整个文件加载到内存中。特定行的索引在列表 L = [2, 5, 15, 98, ...]
中给出,我的 csv 文件如下所示:
Col 1, Col 2, Col3
row11, row12, row13
row21, row22, row23
row31, row32, row33
...
使用提到的想法 我使用以下命令读取行
with open('~/file.csv') as f:
r = csv.DictReader(f) # I need to read it as a dictionary for my purpose
for i in L:
for row in enumerate(r):
print row[i]
我立即收到以下错误:
IndexError Traceback (most recent call last)
<ipython-input-25-78951a0d4937> in <module>()
6 for i in L:
7 for row in enumerate(r):
----> 8 print row[i]
IndexError: tuple index out of range
问题1.看来我在这里使用for
循环显然是错误的。关于如何解决这个问题有什么想法吗?
另一方面,以下方法可以完成工作,但速度太慢:
def read_csv_line(line_number):
with open("~/file.csv") as f:
r = csv.DictReader(f)
for i, line in enumerate(r):
if i == (line_number - 2):
return line
return None
for i in L:
print read_csv_line(i)
问题 2。关于如何改进这种遍历整个文件直到到达第 i 行然后打印的基本方法有什么想法吗?
for row in enumerate(r):
将拉取元组。然后,您正尝试 select 来自 2 元素元组的第 i 个元素。
例如
>> for i in enumerate({"a":1, "b":2}): print i
(0, 'a')
(1, 'b')
此外,由于字典是哈希表,因此不一定会保留您的初始顺序。例如:
>>list({"a":1, "b":2, "c":3, "d":5})
['a', 'c', 'b', 'd']
假设 L
是一个包含您想要的行号的列表,您可以这样做:
with open("~/file.csv") as f:
r = csv.DictReader(f)
for i, line in enumerate(r):
if i in L: # or (i+2) in L: from your second example
print line
这样 :
- 你只读了一次文件
- 您没有将整个文件加载到内存中
- 你只会得到你感兴趣的台词
唯一需要注意的是,即使 L = [3]
也需要读取整个文件
一个文件没有 "lines" 或 "rows"。您认为 "line" 是 "what is found between two newline characters"。因此,如果不阅读它之前的行,您将无法阅读第 n 行,因为您无法计算换行符。
答案 1:如果您考虑您的示例,但使用 L=[9],展开您的循环将得到:
i=9
row = (0, {'Col 2': 'row12', 'Col 3': 'row13', 'Col 1': 'row11'})
如你所见,row 是一个有两个成员的元组,调用 row[i]
意味着 row[9]
,因此出现 IndexError。
答案2:这很慢,因为你每次都在读取文件直到行号。在您的示例中,您阅读了前 2 行,然后是前 5 行,然后是前 15 行,然后是前 98 行,等等。所以您已经阅读了前 5 行 3 次。您可以创建一个仅 returns 您想要的行的生成器(注意,行号将从 0 开始索引):
def read_my_lines(csv_reader, lines_list):
for line_number, row in enumerate(csv_reader):
if line_number in lines_list:
yield line_number, row
所以当你想处理线条时,你会这样做:
L = [2, 5, 15, 98, ...]
with open('~/file.csv') as f:
r = csv.DictReader(f)
for line_number, line in read_my_lines(r, L):
do_something_with_line(line)
* 编辑 *
这可以进一步改进,以便在您阅读完所需的所有行后停止阅读文件:
def read_my_lines(csv_reader, lines_list):
# make sure every line number shows up only once:
lines_set = set(lines_list)
for line_number, row in enumerate(csv_reader):
if line_number in lines_set:
yield line_number, row
lines_set.remove(line_number)
# Stop when the set is empty
if not lines_set:
raise StopIteration
只是为了总结伟大的想法,我最终使用了这样的东西: L
可以相对快速地排序,在我的例子中它实际上已经排序了。因此,与其在 L
中进行多次成员资格检查,还不如对其进行排序,然后只检查每个索引与它的第一个条目。这是我的一段代码:
count=0
with open('~/file.csv') as f:
r = csv.DictReader(f)
for row in r:
count += 1
if L == []:
break
elif count == L[0]:
print (row)
L.pop(0)
请注意,一旦我们完成 L
一次,它就会停止。
我正在尝试读取大型 csv 文件的某些特定行,但我不想将整个文件加载到内存中。特定行的索引在列表 L = [2, 5, 15, 98, ...]
中给出,我的 csv 文件如下所示:
Col 1, Col 2, Col3
row11, row12, row13
row21, row22, row23
row31, row32, row33
...
使用提到的想法
with open('~/file.csv') as f:
r = csv.DictReader(f) # I need to read it as a dictionary for my purpose
for i in L:
for row in enumerate(r):
print row[i]
我立即收到以下错误:
IndexError Traceback (most recent call last)
<ipython-input-25-78951a0d4937> in <module>()
6 for i in L:
7 for row in enumerate(r):
----> 8 print row[i]
IndexError: tuple index out of range
问题1.看来我在这里使用for
循环显然是错误的。关于如何解决这个问题有什么想法吗?
另一方面,以下方法可以完成工作,但速度太慢:
def read_csv_line(line_number):
with open("~/file.csv") as f:
r = csv.DictReader(f)
for i, line in enumerate(r):
if i == (line_number - 2):
return line
return None
for i in L:
print read_csv_line(i)
问题 2。关于如何改进这种遍历整个文件直到到达第 i 行然后打印的基本方法有什么想法吗?
for row in enumerate(r):
将拉取元组。然后,您正尝试 select 来自 2 元素元组的第 i 个元素。
例如
>> for i in enumerate({"a":1, "b":2}): print i
(0, 'a')
(1, 'b')
此外,由于字典是哈希表,因此不一定会保留您的初始顺序。例如:
>>list({"a":1, "b":2, "c":3, "d":5})
['a', 'c', 'b', 'd']
假设 L
是一个包含您想要的行号的列表,您可以这样做:
with open("~/file.csv") as f:
r = csv.DictReader(f)
for i, line in enumerate(r):
if i in L: # or (i+2) in L: from your second example
print line
这样 :
- 你只读了一次文件
- 您没有将整个文件加载到内存中
- 你只会得到你感兴趣的台词
唯一需要注意的是,即使 L = [3]
一个文件没有 "lines" 或 "rows"。您认为 "line" 是 "what is found between two newline characters"。因此,如果不阅读它之前的行,您将无法阅读第 n 行,因为您无法计算换行符。
答案 1:如果您考虑您的示例,但使用 L=[9],展开您的循环将得到:
i=9
row = (0, {'Col 2': 'row12', 'Col 3': 'row13', 'Col 1': 'row11'})
如你所见,row 是一个有两个成员的元组,调用 row[i]
意味着 row[9]
,因此出现 IndexError。
答案2:这很慢,因为你每次都在读取文件直到行号。在您的示例中,您阅读了前 2 行,然后是前 5 行,然后是前 15 行,然后是前 98 行,等等。所以您已经阅读了前 5 行 3 次。您可以创建一个仅 returns 您想要的行的生成器(注意,行号将从 0 开始索引):
def read_my_lines(csv_reader, lines_list):
for line_number, row in enumerate(csv_reader):
if line_number in lines_list:
yield line_number, row
所以当你想处理线条时,你会这样做:
L = [2, 5, 15, 98, ...]
with open('~/file.csv') as f:
r = csv.DictReader(f)
for line_number, line in read_my_lines(r, L):
do_something_with_line(line)
* 编辑 *
这可以进一步改进,以便在您阅读完所需的所有行后停止阅读文件:
def read_my_lines(csv_reader, lines_list):
# make sure every line number shows up only once:
lines_set = set(lines_list)
for line_number, row in enumerate(csv_reader):
if line_number in lines_set:
yield line_number, row
lines_set.remove(line_number)
# Stop when the set is empty
if not lines_set:
raise StopIteration
只是为了总结伟大的想法,我最终使用了这样的东西: L
可以相对快速地排序,在我的例子中它实际上已经排序了。因此,与其在 L
中进行多次成员资格检查,还不如对其进行排序,然后只检查每个索引与它的第一个条目。这是我的一段代码:
count=0
with open('~/file.csv') as f:
r = csv.DictReader(f)
for row in r:
count += 1
if L == []:
break
elif count == L[0]:
print (row)
L.pop(0)
请注意,一旦我们完成 L
一次,它就会停止。