909
魔獸
Pandas並非完美無缺
更多深度文章,請關注雲計算頻道:https://yq.aliyun.com/cloud
pandas的一些關鍵問題,以及介紹如何處理這些問題有效的解決方案。
Python用到的地方比較少。近幾年Pandas還不是大家處理數據時候的首選,他們通常使用R,SAS,SPSS,Hadoop或MATLAB。
pandas的內部體係結構有一些不足,這並不奇怪。2011年夏季,我設計了一個被稱為BlockManagerNumPy數組來管理內部的數據列pandas.DataFrame
BlockManager和pandas耦合到NumPy上,整體的內部聯係已經很好的為這個項目提供了服務,但如今這些同時也是導致pandas用戶在大型數據集中工作的出現的問題的一個根本原因。
2011年我並沒有考慮分析100 GB或1 TB的數據集。如今,我對pandas的準則是,你的數據集的大小應該是RAM的5到10倍。所以如果你有一個10 GB的數據集,那麼如果你想避免內存管理問題的話,你應該有大約64G、最好是128GB的RAM。
Pandas的首個準則:數據集的大小應該是RAM的5到10倍。
DataPad,Badger,我在Cloudera的時間
Chang Shepandas合作者)在2013年合作開始做DataPad。我們想要使用新興的PyData堆棧為我們正在構建的可視化分析應用程序提供支持,但是我們遇到了一些嚴重的性能問題,特別是在雲(cloud)這方麵,因為來自DataPad應用程序的分析查詢的響應並不適合pandas。
pandas的特征集簡化為簡單的要點,我們稱之為Badger。我發現通過針對優化本地數據使用連續不變的柱狀數據結構,我可以在優化過程中獲得2-20倍的性能提升,最大的改善是在字符串處理上。
2013年11月“我討厭pandas的十個方麵”的演講。
1.內部構件離“metal”太遠。
2.不支持內存映射數據集。
3.數據庫和文件攝取/導出性能不佳。
4.Warty缺少數據支持。
5.缺乏內存使用的透明度和RAM管理。
6.對分類數據的弱支持。
7.複雜的組合操作笨拙而又緩慢。
8.將數據附加到DataFrame很繁瑣而且成本非常高。
9.有限的,不可擴展的類型元數據。
10.急切的評估模式,無查詢規劃。
11.“慢”,算法不適用於處理較大數據集。
Badger中的一些問題,但在解決DataPad問題的方案上能力有限。幸運的是,我搬到了Cloudera,那裏有很多資料庫和大數據係統開發人員的經驗可供我學習。
Cloudera,我開始關注Impala,Kudu,Spark,Parquet等大型數據存儲和分析係統。由於Python和pandas從未涉及這些任何一個項目,因此與其建立集成很困難。最大問題是數據交換,特別是
2015年初,我一直在研究所謂的“columnar data middleware)”,它提供零拷貝訪問,對字符串JSON數據類型的所有類型。像Badger的原型運行時一樣,這種格式需要針對本地數據進行優化,以便我們可以以最大速度的進行評估查詢。
Apache Drill,Impala,Kudu,Spark等的人。在2015年下半年,為了創建一個沒有軟件供應商關聯的中立“安全空間”,我們與Apache軟件基金會合作建立了Apache Arrow
Arrow是下一代數據科學工具的關鍵技術。
2015年底,我寫了pandas核心實現,我們可以稱之為pandas2。Pandas是一個pandas內部錯誤的評估,在這個問題上大家的意見基本一致,但是在不破壞現有的pandas用戶社區情況下解決它們還是個問題。在這段時間裏,我專注於構建計算基礎設施,此過程pandas用戶基本上看不見。
Arrow解決這“10件事”了嗎?
Arrow的C++實現工具為pandas等項目提供必要的內存分析基礎架構:
1.針對分析處理性能優化的運行時列式存儲格式
3.可擴展類型的元數據,用於描述現實世界係統中發生的各種平麵和嵌套數據
Arrow C++項目所缺少的是(但這種情況不會持續太久):
1.一個全麵的分析功能的“內核”庫
2.圖形數據流執行的邏輯運算符圖(僅在數據幀方麵,可以參考一下TensorFlow或PyTorch)
3.用於並行評估運算符圖的多核心調度器
“10個方麵”,以及如何通過Arrow項目來解決。
1.更接近“metal”
Arrow每列所有內存(無論是字符串類型,number類型還是嵌套類型)都排列在針對隨機訪問(單個值)和掃描(多個相鄰的值)性能優化的連續內存緩衝區中。這個想法是,即使使用字符串或其他非數字類型,也可以在循環訪問表列中的數據時盡量減少CPU或GPU高速緩存時未命中項。
pandas裏,字符串數組是數組PyObject的指針,而實際的字符串數據存在於PyBytes或PyUnicode整個堆結構進程中。作為開發人員,對於處理這些對象的內存限製,我們無能為力。在Python中,簡單的字符串'wes'占用了52個字節的內存。''占用49字節。
Arrow中,每個字符串緊鄰內存中的前一個,因此你可以掃描字符串中的所有數據,而不會出現任何高速緩存未命中的問題。在“metal”上處理連續字節。
Arrow的C / C ++ API意味著對Python不了解的應用程序可以消耗或產生原始的Arrow表,並在進程中或通過共享內存/內存映射來共享它們。Pandas缺少用於數據幀的C或Cython API是另一個大問題。
2.內存映射巨大的數據集
pandas最大的內存管理問題是數據必須完全加載到RAM中才能處理的要求。Pandas的內部BlockManager太複雜了,無法在任何實際的內存映射設置中使用,因此,隻要你創建pandas.DataFrame,都將執行不可避免的轉換和複製。
Arrow序列化設計提供了一個“數據header”RAM更大的數據集,並在其原狀上評估pandas類型的算法,而不必將其加載到內存中,就像你現在必須使用pandas一樣。你可以從1TB的桌麵中間讀取1MB,而隻需支付總共1MB的隨機讀取內存。此技術采用現代固態驅動器,這是一個很好的策略。
3.高速數據采集和導出(數據庫和文件格式)
Arrow的高效內存布局和豐富的元數據使其成為數據庫和柱狀存儲格式(如Apache Parquet)的入站數據的理想容器。
Arrow的原始構造之一是“記錄批處理流”
Parquet格式的高速連接器ODBC的數據庫連接的turbodbc
4.“正確”的丟失數據
Arrow中的所有缺失數據都表示為一個填充位數組,並與其他數據分開。這使得丟失數據處理在所有數據類型中都是簡單和一致的。你還可以使用快速逐位內置的硬件運算符和SIMD對null bits(AND位圖或計數位)進行分析。
pandas,我們不能假設數組沒有空標簽值,因此大多數分析都有額外的空檢查,雖然這會損害性能。如果沒有空值,你甚至不需要分配位數組。
NumPy中本來就支持丟失數據,所以隨著時間的推移,我們不得不實現我們自己的更為關鍵的性能關鍵算法的空閑版本。最好是從頭開始將所有的算法和內存管理內置到null-handling中。
5.保持內存分配檢查
pandas中,所有的內存都是由NumPy或Python解釋器所擁有,並且很難精確地測量給定的pandas.DataFrame的內存使用量。
Arrow的C ++實現中,所有內存分配都在中央“內存池”中“小心的”跟蹤,因此你可以確定任何給定時間內RAM中的Arrow內存數量。通過使用帶有父子關係的“子池(subpools)”,你可以精確地測量算法中的“高水位”,以了解分析操作時的內存使用的峰值情況。這種技術在數據庫中常見用於監視或限製內存在操作員評估中的使用。如果你知道你將要超出可用的RAM,則可以應用緩解策略,如溢出到磁盤(內存映射數據集到磁盤上的能力當然最為關鍵的)。
Arrow裏,其內存中是一成不變的或寫入時複製的。在任何給定的時間,你可以知道另一個數組是否引用一個你可以看到的緩衝區。這可以使我們避免防禦性的複製。
6.支持分類數據
2013年發表演講時,pandas還沒有pandas.Categorical類型,這個類型是之後實現的。對於不在Numpy的數據類型,pandas的解決方法一直是有點“愚蠢”的。如果不用pandas,那你就不能使用pandas.Categorical。擴展dtypes的方法已經實現了,但由於pandas與NumPy的緊密耦合,有些束縛和局限。
Arrow中,categories數據是最厲害的功能,同時在內存中,網絡上或者共享內存中我們可以連續而又連續的優先體現。我們支持在多個數組之間共享categories(在Arrow中稱為字典)。
Pandas有其他用戶自定義的類型:datetime與時區和周期。我們打算能夠支持Arrow中的邏輯數據類型,以便特定的係統可以使用Arrow完整的地傳輸其數據,而無需更改Arrow格式的文檔。
7.更好的組合應用操作
Arrow之所以有用是因為能使groupby操作更容易並行化,由於這裏也列出的有其他問題,所以不可能使df.groupby(...).apply(f)操作完全並行化。
pandas複雜應用操作的API。
8.附加到數據幀
pandas中,DataFrame(數據幀)中每列中的所有數據必須位於相同的NumPy數組中。這是一個限製性的要求,所以經常會導致內存加倍和額外的計算來連接Series和DataFrame對象。
Arrow C ++中的表中的列可以分塊,因此附加到表是零複製操作,所以不需要獨特的計算或內存分配。通過為流,分塊表設計前端,附加到現有的內存中的表相對於pandas來說在計算上是便宜的。用於分塊或流數據的設計對於實現out-of-core算法也是必不可少的,因此我們也為處理大於內存中的數據集奠定了基礎。
9.添加新的數據類型
1.添加新的元數據
2.為分析中運算符的實現創建動態調度規則
3.通過操作保留元數據
“currency(通用)”類型可以包含當前類型的字符串,數據在物理上表示為float64或decimal。因此,你可以按照數字表示方式對currency(通用)類型進行計算,然後在數值操作中執行currency(通用)類型的元數據。
Arrow中,我們已經將從計算的細節中將元數據表現層與元數據的保護層分離了。在C ++的實現中,我們一直在為用戶自定義的類型進行規劃,因此當我們更多地關注構建一個分析引擎時,目標是創建用戶自定義的運營商調度和元數據的提升規則。
10/11。查詢計劃,多核執行
df[df.c < 0].d.sum()pandas創建一個臨時名為df[df.c < 0]DataFrame,然後對該d列的臨時對象求和。如果 df df.d[df.c < 0].sum()
Arrow的分析引擎的一部分,我們還計劃使用在進程中的多核調度程序構建一個輕量級的“查詢計劃程序”實體,以使多種算法能夠並行化和有效地評估。在圖形數據流執行的領域(特別是在最近的ML,如TensorFlow和PyTorch)中有大量現有技術,所以這相當於創建一個圖形數據流引擎,其原始數據單位是一個Arrow表。
On Dask
DaskSpark,以及其他這樣的項目)以及它如何幫助pandas展現更好的表現和可擴展性。其實在各個方麵都有,比如:
1.將大型數據集拆分成單獨的線程或單獨的進程來工作
2.從RAM中消除不再需要的pandas數據
Dask通過並行運行pandas.read_csv然後在整個數據集上運行groupby,來輕鬆讀取CSV文件目錄。Dask模型的一個問題是使用pandas作為黑盒子,但dask.dataframe不會解決pandas的內在性能和內存使用問題,而是將它們分散在多個進程中,並小心地通過拒絕一次性處理太大的數據來減少問題,從而導致一個非預期的MemoryError錯誤。
pandas的內存管理和IO的性能挑戰使得Dask工作比通過更高效的內存運行要慢得多。
本文由北郵@愛可可-愛生活 老師推薦,阿裏雲雲棲社區組織翻譯。
Apache Arrow and the "10 Things I Hate About pandas"》
作者: Wes McKinney
文章為簡譯,更為詳細的內容,請查看原文
最後更新:2017-09-24 21:32:43