題目是希望用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的一些技巧可以移步我這個回答