题目是希望用python\pandas(可能有一些现成脚本)单机16GB内存处理100GB的csv数据。
在2022年来看问题,有几种思路
1.用dask。这个是肯定可以解决问题的。dask项目的设计理念,就是把数据切分,然后分别处理,同时保持pandas的语法不变。可以用多节点,也可以单机。
他官网介绍如下 https://www. dask.org/# blog
这里说的「单机跑100GB数据」简直完美贴合题目啊。
2. 用Dask-cuDF。比dask效率更高的方法就是用RAPIDS生态下的Dask-cuDF,前提是要能弄到一张或多张nvidia显卡(这个是nvidia主导,社区开发者踊跃参与的一套生态)。用cuDF的话,会把所有数据load到显存中,而Dask-cuDF和dask一样会对数据先进行切分,所以显存大小不会成为瓶颈,公司项目的话可以买或者借一个16GB显卡也不算太高成本。
Multi-GPU with Dask-cuDF
Multi-GPU with Dask-cuDF #cuDF is a single-GPU library. For Multi-GPU cuDF solutions we use Dask and the dask-cudf package, which is able to scale cuDF across multiple GPUs on a single machine, or multiple GPUs across many machines in a cluster.
Dask DataFrame was originally designed to scale Pandas, orchestrating many Pandas DataFrames spread across many CPUs into a cohesive parallel DataFrame. Because cuDF currently implements only a subset of the Pandas API, not all Dask DataFrame operations work with cuDF.
3. 最装逼的办法就是只用pandas做,不一定能成功,取决于你的数据是什么样的。我用8GB内存单机分析过30G的csv文件。csv这种plain text存储方式占用硬盘的大小会比读入内存后的占用的要大。特别是特征特别稀疏的那种数据,比如标签类型的数据,绝大部分是空值的那种。比如这个问题,就是400MB多的csv变成xlsx只要1MB多
.csv的文件为什么这么大?
不过read_csv的IO操作有额外的内存开销,会远远大于你的内存,所以要一批一批的读。例如
chunksize
=
1
_000_000
# 根据情况写每次读取的量
dtype_map
=
{
'a'
:
np
.
uint8
}
# 用最节省空间又能完全保证信息量的数据类型
# chunks不是dataframe的集合,而是一个TextFileReader对象,文件还没有读
# 后面逐个遍历时,一个一个地读
chunks
=
pd
.
read_csv
(
'large.csv'
,
chunksize
=
chunksize
,
dtype
=
dtype_map
)
#
# 然后每个chunk进行一些压缩内存的操作,比如全都转成sparse类型
# string类型比如,学历,可以转化成sparse的category变量,可以省很多内存
sdf
=
pd
.
concat
(
chunk
.
to_sparse
(
fill_value
=
0.0
)
for
chunk
in
chunks
)
#很稀疏有可能可以装的下
#然后在sparse数据类型上做计算
sdf
.
sum
()
或者每次对单个chunk做统计,然后最后汇总。这个可能难度有点高,看需要做的什么操作。
当然,大部分用户还是建议选择方法1或2。值得一提是,pandas社区的很多人,包括核心维护者都深度与了dask项目。比如 TomAugspurger - Overview。(他原来是pandas的维护者,现在是dask维护者)
而Pandas的创造者,Wes McKinney现在也和nVidia一起在搞RAPIDS,因为RAPIDS底层用他在搞的Apache Arrow Announcing Ursa Labs's partnership with NVIDIA 。所以我很看好这个生态,未来很可能用dask-cuDF会成为主流的数据处理、数据分析工具(还要看显卡价格是否能回归正常)
关于pandas的一些技巧可以移步我这个回答