Python_tips-chunksize(iterator)

万壑松风知客来,摇扇抚琴待留声

简述:

昨天晚上本来准备写这篇的,但是写着写着跑偏了。上一篇文章介绍了 read_csv 函数的常用参数使用场景,其中两个参数的说明留到本篇介绍(时间太晚,内容相对多所以。。。)。在做数据处理时大多数情况下由于在本地使用数据,待读取数据集量较大,读入内存十分缓慢甚至读取错误。面对这种问题,可以通过 read_csv 读取数据时指定参数 chunksizeiterator 来变相减缓这种问题。

参数 chunksize:

若在使用 read_csv 读取文件时指定 chunksize 参数,则可以将读取文件按照指定分块读取,返回的结果为可迭代对象 TextFileReader。若不能严格按照指定分块数进行划分,则迭代对象的最后一个部分按实际情况减少数据行。对于返回的可迭代对象,可以通过循环的方式读取每个分块,每个分块的数据集大小就是 chunksize 所指定的大小,当然也可以使用 get_chunk 方法获取数据行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 保存测试数据如下生成
test_data = pd.DataFrame({'a':np.arange(1,21),'b':list('mmmmmmmmmmnnnnnnnnnn')})

a b
0 1 m
1 2 m
2 3 m
3 4 m
4 5 m
5 6 m
6 7 m
7 8 m
8 9 m
9 10 m
10 11 n
11 12 n
12 13 n
13 14 n
14 15 n
15 16 n
16 17 n
17 18 n
18 19 n
19 20 n

指定 chunksize 参数分块迭代读取数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 按照 5 分块的大小读取数据
df = pd.read_csv('test_data.csv', index_col=0, chunksize=5)
for chunk in df:
print(chunk)

a b
0 1 m
1 2 m
2 3 m
3 4 m
4 5 m
a b
5 6 m
6 7 m
7 8 m
8 9 m
9 10 m
a b
10 11 n
11 12 n
12 13 n
13 14 n
14 15 n
a b
15 16 n
16 17 n
17 18 n
18 19 n
19 20 n

说明:此处数据刚好分为 5 分块,如不能整除则最后一部分数据等于最小余数量。

参数 iterator:

chunksize 参数类似分块读取数据,区别是 iterator 参数只有 bool 值,默认为 False,若设置为 True 则返回的也是可迭代对象,可以通过 get_chunk 函数返回指定数据大小(当然设置了 chunksize 参数也可以使用)。一个实际使用情况,若面对一个很大的位置文件,我们需要了解数据再做处理,这时便可以通过指定 iterator=True 读取文件,然后通过 get_chunk 来指定返回数据量。

1
2
3
4
5
6
7
8
9
10
# 面对一个大文件,设置参数 iterator ,打印 5 行数据
df = pd.read_csv('test_data.csv', index_col=0, iterator=True)
print(df.get_chunk(5))

a b
0 1 m
1 2 m
2 3 m
3 4 m
4 5 m

to_csv 的 mode 参数:

关于读取有了可以分块处理大文件的方法,那么写大文件同样有着这样的麻烦。所以这里再添加一个小技巧,讲讲如何处理大文件的写入。pandas 提供了 read_csv 读取文件,也就给了 to_csv 来写入文件(同样有 chunksize 参数),眼花缭乱的 to_csv 参数中有一个 mode 参数,用来指明数据写入文件的方式,默认值为 w (应该不陌生其含义吧)。所以可以在该参数上做文章,指定参数为 a ,通过追加的方式写入文件,这样就可以分块写入,避免了直接写入大量数据。(经测试,追加写入时最好指定 header=False 避免列名的重复写入)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 追加方式可以结合前面的 chunksize 参数来处理大数据
df = pd.read_csv('test_data.csv', index_col=0, chunksize=5)
for chunk in df:
chunk['a'] = chunk['a'].apply(lambda x: x**2)
chunk.to_csv('to_chunk.csv', mode='a', header=False) # header=False 防止重复写入列名


0 1 m
1 4 m
2 9 m
3 16 m
4 25 m
5 36 m
6 49 m
7 64 m
8 81 m
9 100 m
10 121 n
11 144 n
12 169 n
13 196 n
14 225 n
15 256 n
16 289 n
17 324 n
18 361 n
19 400 n

终端完整显示 DataFrame 数据:

已经说到了大数据情况,那就再补充一个小知识。平时当 DataFrame 或其它形式的数据集过大时,在终端显示就会出现省略的情况,这样的好处是避免了太多数据的输出,造成显示问题,但同时也可能防止了我们观察完整数据。所以这种情况可以通过设置 pandas 参数来解决。

1
2
3
4
5
6
# 设置在数据输出之前即可
import pandas as pd

pd.set_option('display.max_columns', None) # 显示所有列数据
pd.set_option('display.max_rows', None) # 显示所有行数据
pd.set_option('display.width',None) # 一行数据不分段显示

说明:上面的 None 表示全部,可以设置为整数形式指定数值。关于这个显示问题还有很多的参数设置,通过个人需求来得到不同样式,可以参考这里的官方文档

总结:

本文介绍了简单介绍了读取大文件时,可以通过 read_csv 函数的两个参数 chunksize、iterator 来减缓问题。同样面对写入大数据时可以结合 chunksize 与 to_csv 函数的 mode (to_csv 也有 chunksize 参数哦)。此外补充了终端完整显示数据的方法。对于该大数据问题,这里只是粗浅的给出了一种解决方式,其它高效合理的方法使用或参数调整日后再做整理。