據(jù)分析Pandas全攻略)
前言Pandas 是 Python 生態(tài)里做表格數(shù)據(jù)處理最常用的第三方庫third-party library 它建立在 NumPy 之上提供了兩個核心數(shù)據(jù)結(jié)構(gòu)一維的Series和二維的DataFrame。 日常說的用 Python 做數(shù)據(jù)分析十有八九指的就是 pandas。需要先說清楚一件事pandas 不是標(biāo)準(zhǔn)庫必須單獨安裝pip install pandas 它也不在本文的驗證環(huán)境里——本機(jī)沒有 Python 解釋器、沒有 pandas所以下文的示例只能逐行人工推演無法運行驗證。凡是涉及具體參數(shù)的地方都以 Pandas 官方文檔為準(zhǔn)本文只保證概念和調(diào)用形式準(zhǔn)確。另一個常見誤解是把 pandas 當(dāng)成Excel 的替代品。pandas 的數(shù)據(jù)模型是列式 索引 它擅長的是批量向量化運算、分組聚合和連接而不是像 Excel 那樣逐個單元格編輯。 理解這一點后面的loc/iloc、鏈?zhǔn)劫x值、apply與向量化的取舍就都順了。一、兩個核心數(shù)據(jù)結(jié)構(gòu)Series是帶標(biāo)簽的一維數(shù)組DataFrame是帶行標(biāo)簽和列標(biāo)簽的二維表。 可以把DataFrame理解成共享同一個行索引index的多個Series。# pandas 1.0 均可使用示例需先 pip install pandasimport pandas as pds pd.Series([10, 20, 30], index[a, b, c])df pd.DataFrame({name: [Alice, Bob, Cara],age: [25, 30, 28],city: [Beijing, Shanghai, Beijing],})print(df.index) # RangeIndex(start0, stop3, step1)print(df.columns) # Index([name, age, city], dtypeobject)print(df.dtypes) # 每列各自的數(shù)據(jù)類型索引index是 pandas 區(qū)別于純 NumPy 數(shù)組的關(guān)鍵它讓按標(biāo)簽取值和 按位置取值成為兩套不同的語義也正是loc與iloc分野的來源。dtypes尤其要看。常見類型有int64、float64、object、bool 較新的 pandas 還支持可空類型Int64大寫 I、boolean、string。object通常是字符串或混合類型運算性能一般能轉(zhuǎn)成專門的類型就轉(zhuǎn)。二、數(shù)據(jù)讀取與寫出pandas 的 I/O 是它最受歡迎的部分常見的讀取函數(shù)命名很規(guī)律。# pandas 1.0df pd.read_csv(data.csv, encodingutf-8)df pd.read_excel(data.xlsx, sheet_name0) # sheet_name 默認(rèn) 0即第一個表# df.to_csv(out.csv, indexFalse, encodingutf-8)要點read_csv的encoding參數(shù)在 Windows 上尤其重要中文文件常見utf-8與gbk兩種情況讀出來亂碼先懷疑編碼。read_excel的參數(shù)叫sheet_name不是舊版的sheetname可傳表名、表序號或傳None一次性讀全部表并返回字典。to_csv/to_excel的indexFalse能避免把行號也寫進(jìn)文件。場景常用函數(shù)關(guān)鍵參數(shù)CSV 文本read_csvsep、encoding、usecolsExcelread_excelsheet_name、header、usecolsSQL 數(shù)據(jù)庫read_sqlsql、con、params寫出 CSVto_csvindex、encoding寫出 Excelto_excelsheet_name、index注意read_sql的簽名是read_sql(sql, con, ...)sql 在前、連接在后 順序記反是最常見的低級錯誤。參數(shù)化查詢請用params不要自己拼字符串。三、選擇、過濾與賦值取值有三套入口必須分清# pandas 1.0df[age] # 取一列返回 Seriesdf[[name, age]] # 取多列返回 DataFrame注意雙重方括號df.loc[0, name] # 按標(biāo)簽取df.iloc[0, 0] # 按位置取df[df[age] 26] # 布爾過濾df[age]返回Seriesdf[[age]]返回DataFrame。 方括號里給字符串是選列給布爾序列是過濾行——同一套語法兩種含義 這是初學(xué)者最容易混淆的地方。賦值優(yōu)先用loc避免鏈?zhǔn)劫x值# pandas 3.0 起默認(rèn)啟用寫時復(fù)制Copy-on-Writedf.loc[df[age] 26, group] senior從 pandas 3.0 開始寫時復(fù)制Copy-on-Write簡稱 CoW成為默認(rèn)行為 過去那種改了卻報 SettingWithCopyWarning、或者改了個寂寞的情況有了統(tǒng)一語義 任何切片得到的都是邏輯副本修改它不會影響原對象除非你顯式用.loc在原對象上改。 新版里SettingWithCopyWarning這個警告本身已經(jīng)被移除。四、分組聚合與合并分組groupby的語義是拆分—應(yīng)用—合并split-apply-combine# pandas 1.0result df.groupby(city, as_indexFalse)[age].mean()# 多列多函數(shù)聚合agg df.groupby(city).agg({age: [mean, max]})合并merge對應(yīng) SQL 的 JOIN# pandas 1.0merged pd.merge(orders, users, howleft, onuser_id)how取值inner內(nèi)連接默認(rèn)、left左連接、right右連接、outer外連接、cross笛卡爾積。左右兩側(cè)列名不同時用left_on/right_on 同名但需要區(qū)分時用suffixes控制后綴。五、一個完整的小例子下面把讀取、清洗、分組、寫出串起來。代碼結(jié)構(gòu)完整但請以官方文檔核對參數(shù)。# pandas 1.0import pandas as pddef summarize(path: str) - pd.DataFrame:df pd.read_csv(path, encodingutf-8)# 1) 列名去空格避免 name 與 name 被當(dāng)成兩列df.columns df.columns.str.strip()# 2) 數(shù)值列缺失按 0 填充字符串列缺失留空df[amount] df[amount].fillna(0)# 3) 按城市分組求和out (df.groupby(city, as_indexFalse).agg(total(amount, sum), orders(amount, size)).sort_values(total, ascendingFalse))return outif __name__ __main__:summary summarize(orders.csv)print(summary.head())注意agg(total(amount, sum))是命名聚合寫法關(guān)鍵字是結(jié)果列名 值是「源列名, 聚合函數(shù)」的元組。這是 pandas 0.25 起提供的語法比agg({amount: sum})再改名更省事。拿不準(zhǔn)時退回到較老的寫法更保險。常見坑點把df[age]和df[[age]]當(dāng)成一樣?type(df[age])以為得到表格實際是Series后面df[age][new_col]直接報錯 ? 需要保留二維結(jié)構(gòu)就用雙括號df[[age]]得到DataFrame用鏈?zhǔn)劫x值改數(shù)據(jù)?df[df[age] 26][group] senior在舊版報SettingWithCopyWarning在新版默默無效 ?df.loc[df[age] 26, group] senior一次定位、一次賦值read_excel記憶成舊參數(shù)名?pd.read_excel(a.xlsx, sheetnameSheet1)?pd.read_excel(a.xlsx, sheet_nameSheet1)新版本用sheet_nameread_sql把連接和 SQL 寫反?pd.read_sql(conn, SELECT * FROM t)?pd.read_sql(SELECT * FROM t, conn)sql在前、con在后拼 SQL 字符串傳參數(shù)?pd.read_sql(fSELECT * FROM t WHERE id{uid}, conn)有注入風(fēng)險 ?pd.read_sql(SELECT * FROM t WHERE id%(uid)s, conn, params{uid: uid})沒看dtypes就算數(shù)? 直接把object列拿去做減法報TypeError? 先df.dtypes檢查用pd.to_numeric或astype轉(zhuǎn)成數(shù)值類型再算groupby默認(rèn)把分組鍵變成索引? 分組后out[city]報 KeyError因為 city 跑到索引里去了 ? 加as_indexFalse讓分組鍵保持為普通列總結(jié)主題關(guān)鍵點數(shù)據(jù)結(jié)構(gòu)Series一維、DataFrame二維都帶索引讀取read_csv看encodingread_excel用sheet_name取值方括號選列/過濾loc按標(biāo)簽iloc按位置賦值用loc別鏈?zhǔn)劫x值3.0 起 CoW 為默認(rèn)分組groupby是拆分—應(yīng)用—合并注意as_index合并merge(how...)對齊 SQL JOIN參數(shù)化查詢防注入pandas 的學(xué)習(xí)曲線主要卡在索引語義上先把loc/iloc和布爾過濾練熟 再去理解分組與合并最后才是性能優(yōu)化。記住它是第三方庫、要按官方文檔核對參數(shù) 多寫多查比死記 API 更靠譜。