Python?Pandas數(shù)據(jù)分析的使用完整教學(xué)
一、 數(shù)據(jù)接入層:高效 I/O 與現(xiàn)代數(shù)據(jù)格式
在企業(yè)中,數(shù)據(jù)來源五花八門(CSV、Excel、SQL數(shù)據(jù)庫、數(shù)據(jù)湖Parquet)。“如何把數(shù)據(jù)快速且省內(nèi)存地讀進(jìn)來” 是分析的第一步。
1.1 傳統(tǒng)格式的“避坑”讀取
import pandas as pd
import numpy as np
# 新手做法:直接讀取,導(dǎo)致內(nèi)存撐爆或類型推斷錯(cuò)誤
# df = pd.read_csv('huge_orders.csv')
# 專業(yè)做法:精準(zhǔn)控制列、類型與分塊
# 1. 使用 usecols 只讀需要的列
# 2. 使用 dtype 預(yù)先指定類型,避免 object 和 int64 的內(nèi)存浪費(fèi)
# 3. 使用 parse_dates 直接解析時(shí)間
dtypes = {
'order_id': 'int32',
'user_id': 'int32',
'status': 'category', # 低基數(shù)枚舉字段使用 category
'amount': 'float32'
}
df = pd.read_csv(
'huge_orders.csv',
usecols=['order_id', 'user_id', 'status', 'amount', 'order_time'],
dtype=dtypes,
parse_dates=['order_time']
)
1.2 超大文件的分塊處理 (Chunking)
當(dāng) CSV 文件達(dá)到幾十 GB,超出單機(jī)內(nèi)存時(shí),使用 chunksize 進(jìn)行流式處理。
chunk_iter = pd.read_csv('billion_rows.csv', chunksize=100_000)
total_revenue = 0
for chunk in chunk_iter:
# 在每個(gè) chunk 上進(jìn)行聚合操作,最后合并結(jié)果
total_revenue += chunk['amount'].sum()
1.3 擁抱現(xiàn)代數(shù)據(jù)湖格式:Parquet
強(qiáng)烈建議:在內(nèi)部流轉(zhuǎn)大量數(shù)據(jù)時(shí),徹底拋棄 CSV,改用 Parquet。它支持列式存儲(chǔ)、壓縮率極高,且完美保留數(shù)據(jù)類型。
# 寫入 Parquet (使用 pyarrow 引擎)
df.to_parquet('orders_clean.parquet', engine='pyarrow', compression='snappy')
# 讀取 Parquet (Pandas 2.0+ 推薦開啟 PyArrow 后端)
df_arrow = pd.read_parquet('orders_clean.parquet', dtype_backend='pyarrow')
二、 數(shù)據(jù)診斷層:快速探索與質(zhì)量評(píng)估 (EDA)
拿到數(shù)據(jù)后,不要急于建?;虍媹D,先給數(shù)據(jù)做“全身體檢”。
2.1 一鍵生成數(shù)據(jù)質(zhì)量診斷報(bào)告
def diagnose_dataframe(df: pd.DataFrame) -> pd.DataFrame:
"""數(shù)據(jù)質(zhì)量診斷函數(shù)"""
diag = pd.DataFrame({
'Dtype': df.dtypes,
'Non_Null': df.count(),
'Null_Count': df.isnull().sum(),
'Null_Rate(%)': (df.isnull().sum() / len(df) * 100).round(2),
'Unique_Count': df.nunique(),
'Memory_MB': df.memory_usage(deep=True) / (1024**2)
})
return diag.sort_values('Null_Rate(%)', ascending=False)
# 調(diào)用
diagnose_dataframe(df)
2.2 數(shù)值與分布的快速概覽
# 查看數(shù)值型統(tǒng)計(jì)量,并調(diào)整顯示精度
pd.set_option('display.float_format', lambda x: '%.2f' % x)
print(df.describe(percentiles=[.05, .25, .5, .75, .95, .99])) # 關(guān)注長尾分布
# 查看類別型字段的基數(shù)和Top頻率
print(df.describe(include=['category', 'object']))
三、 數(shù)據(jù)清洗層:臟數(shù)據(jù)處理方案
數(shù)據(jù)清洗占據(jù)了分析師 70% 的時(shí)間。我們需要向量化、自動(dòng)化的清洗策略。
3.1 缺失值的高級(jí)處理
不要無腦 dropna(),要根據(jù)業(yè)務(wù)邏輯處理。
# 1. 業(yè)務(wù)規(guī)則填充:例如“退款金額”缺失代表未退款,填0
df['refund_amount'] = df['refund_amount'].fillna(0)
# 2. 分組填充:用該用戶的歷史均值填充缺失的評(píng)分
df['user_score'] = df.groupby('user_id')['user_score'].transform(
lambda x: x.fillna(x.mean())
)
# 3. 時(shí)間序列插值:對(duì)于連續(xù)的傳感器/財(cái)務(wù)數(shù)據(jù),使用線性或樣條插值
df['daily_revenue'] = df['daily_revenue'].interpolate(method='spline', order=2)
3.2 異常值檢測與截?cái)?(Winsorization)
在計(jì)算均值或訓(xùn)練模型前,必須處理“羊毛黨”或“測試訂單”產(chǎn)生的極端值。
def clip_outliers_iqr(series: pd.Series, factor=1.5) -> pd.Series:
"""基于 IQR 的異常值截?cái)啵ㄉw帽法)"""
Q1 = series.quantile(0.25)
Q3 = series.quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - factor * IQR
upper_bound = Q3 + factor * IQR
return series.clip(lower=lower_bound, upper=upper_bound)
df['amount_clean'] = clip_outliers_iqr(df['amount'])
3.3 字符串的向量化正則提取
從雜亂的文本中提取結(jié)構(gòu)化信息(如從地址中提取省份,從備注中提取優(yōu)惠券碼)。
# 假設(shè) df['remark'] 包含類似 "使用優(yōu)惠券:VIP2026, 免郵" 的文本 # ? 慢速做法:df['remark'].apply(lambda x: re.search(...)) # ? 向量化做法: df['coupon_code'] = df['remark'].str.extract(r'優(yōu)惠券:([A-Z0-9]+)') # 清理隱藏字符并統(tǒng)一小寫 df['city'] = df['city'].str.strip().str.lower().str.replace(r'\s+', ' ', regex=True)
四、 數(shù)據(jù)轉(zhuǎn)換層:重塑、聚合與多表關(guān)聯(lián)
這是 Pandas 最強(qiáng)大的核心區(qū)域,決定了你能否將“明細(xì)數(shù)據(jù)”轉(zhuǎn)化為“業(yè)務(wù)洞察”。
4.1 優(yōu)雅的條件篩選:query()
query() 不僅語法接近 SQL,而且在處理大數(shù)據(jù)框時(shí),由于底層使用 numexpr,內(nèi)存效率遠(yuǎn)高于布爾索引。
# 篩選:高價(jià)值、已完成、特定城市的訂單
target_cities = ['北京', '上海', '廣州', '深圳']
# 使用 @ 引用外部變量
df_filtered = df.query(
"amount > 1000 and status == 'completed' and city in @target_cities"
)
4.2 分組聚合的終極形態(tài):命名聚合
Pandas 0.25+ 引入的命名聚合,讓代碼具備極強(qiáng)的可讀性,直接輸出寬表。
user_stats = df.groupby('user_id').agg(
total_orders=('order_id', 'count'),
total_spend=('amount', 'sum'),
avg_spend=('amount', 'mean'),
first_order=('order_time', 'min'),
last_order=('order_time', 'max')
).reset_index()
# 計(jì)算 RFM 模型中的時(shí)間間隔特征
user_stats['recency_days'] = (pd.Timestamp('2026-05-27') - user_stats['last_order']).dt.days
4.3 數(shù)據(jù)重塑:長寬表轉(zhuǎn)換
melt(寬轉(zhuǎn)長):將多列指標(biāo)融合為一列,方便可視化(如 Seaborn/Matplotlib)。pivot_table(長轉(zhuǎn)寬):生成業(yè)務(wù)報(bào)表。
# 寬轉(zhuǎn)長:將 Jan, Feb, Mar 三列銷售額轉(zhuǎn)為一列
df_long = pd.melt(
df_wide,
id_vars=['store_id', 'region'],
value_vars=['Jan_Sales', 'Feb_Sales', 'Mar_Sales'],
var_name='month',
value_name='sales'
)
# 長轉(zhuǎn)寬:生成 地區(qū) x 月份 的交叉報(bào)表
report = pd.pivot_table(
df_long,
values='sales',
index='region',
columns='month',
aggfunc='sum',
fill_value=0,
margins=True # 添加總計(jì)行/列
)
4.4 多表關(guān)聯(lián)的“防爆”
在大規(guī)模數(shù)據(jù)分析中,merge 導(dǎo)致數(shù)據(jù)行數(shù)翻倍(笛卡爾積)是最常見的生產(chǎn)事故。
# ? 務(wù)必使用 validate 參數(shù)驗(yàn)證關(guān)聯(lián)鍵的唯一性
# 'm:1' 表示左表多對(duì)一右表,如果右表 key 不唯一,直接報(bào)錯(cuò)攔截!
df_final = pd.merge(
orders,
users,
on='user_id',
how='left',
validate='m:1',
suffixes=('_order', '_user')
)
五、 時(shí)序分析層:商業(yè)時(shí)間序列處理
電商、金融、SaaS 等行業(yè),時(shí)間序列是數(shù)據(jù)的靈魂。
5.1 時(shí)間重采樣 (Resample)
將不規(guī)則的交易流水,聚合為標(biāo)準(zhǔn)的日/周/月報(bào)表。
# 確保索引是 DatetimeIndex
df_time = df.set_index('order_time')
# 按日重采樣,計(jì)算每日總GMV和訂單數(shù)
daily_report = df_time.resample('D').agg(
gmv=('amount', 'sum'),
orders=('order_id', 'count')
).fillna(0) # 補(bǔ)齊沒有交易的日期
5.2 滑動(dòng)窗口與滯后特征 (Rolling & Shift)
用于計(jì)算移動(dòng)平均線(MA)、同比/環(huán)比增長率。
# 1. 7日移動(dòng)平均 GMV daily_report['gmv_ma7'] = daily_report['gmv'].rolling(window=7).mean() # 2. 計(jì)算日環(huán)比增長率 (今日 / 昨日 - 1) daily_report['gmv_dod'] = daily_report['gmv'].pct_change(periods=1) # 3. 計(jì)算周同比 (今日 / 7天前 - 1) daily_report['gmv_wow'] = daily_report['gmv'].pct_change(periods=7)
六、 性能優(yōu)化層:突破 Pandas 內(nèi)存與速度瓶頸
當(dāng)數(shù)據(jù)量超過 500 萬行,Pandas 往往會(huì)顯得笨重。掌握以下技巧,能讓你的代碼提速 10x ~ 100x。
6.1 擁抱 Pandas 2.x 的 PyArrow 后端
這是 Pandas 歷史上最偉大的更新。 PyArrow 提供了零拷貝(Zero-copy)讀取、更低的內(nèi)存占用以及原生的缺失值(<NA>)支持。
# 開啟全局 PyArrow 后端 (Pandas 2.0+)
pd.options.mode.dtype_backend = "pyarrow"
# 或者在讀取時(shí)指定
df = pd.read_csv('data.csv', engine='pyarrow', dtype_backend='pyarrow')
# 此時(shí)字符串不再是低效的 object,而是 string[pyarrow],內(nèi)存直降 70%!
6.2 Copy-on-Write (CoW) 機(jī)制
Pandas 2.2 默認(rèn)開啟(3.0 將強(qiáng)制)的 CoW 機(jī)制,徹底解決了“鏈?zhǔn)劫x值警告(SettingWithCopyWarning)”和隱式內(nèi)存復(fù)制問題。
# 開啟 CoW pd.options.mode.copy_on_write = True # 現(xiàn)在,切片操作是懶加載的(視圖),只有當(dāng)你真正修改切片數(shù)據(jù)時(shí),才會(huì)發(fā)生內(nèi)存拷貝。 subset = df[df['amount'] > 100] subset['new_col'] = 1 # 安全,不會(huì)觸發(fā)警告,也不會(huì)意外修改原 df
6.3 消滅apply,走向向量化
apply 本質(zhì)上是 Python 的 for 循環(huán),極慢。永遠(yuǎn)優(yōu)先尋找向量化替代方案。
# 場景:根據(jù)金額劃分等級(jí) (低、中、高)
# ? 極慢的 apply
def get_level(x):
if x < 100: return 'Low'
elif x < 1000: return 'Mid'
else: return 'High'
df['level'] = df['amount'].apply(get_level)
# ? 向量化方案 1:np.select (推薦,邏輯清晰)
conditions = [df['amount'] < 100, df['amount'] < 1000]
choices = ['Low', 'Mid']
df['level'] = np.select(conditions, choices, default='High')
# ? 向量化方案 2:pd.cut (適用于連續(xù)數(shù)值分箱)
df['level_bin'] = pd.cut(df['amount'], bins=[0, 100, 1000, np.inf], labels=['Low', 'Mid', 'High'])
七、 工程實(shí)踐層:鏈?zhǔn)骄幊膛c代碼規(guī)范
在大型項(xiàng)目中,代碼的可讀性和可維護(hù)性與運(yùn)行效率同等重要。推薦使用鏈?zhǔn)讲僮鳎∕ethod Chaining),讓數(shù)據(jù)處理像流水線一樣清晰。
7.1 鏈?zhǔn)讲僮髋cpipe函數(shù)
def drop_outliers(df: pd.DataFrame, col: str) -> pd.DataFrame:
"""自定義清洗管道"""
limit = df[col].quantile(0.99)
return df[df[col] <= limit]
# 一氣呵成的數(shù)據(jù)流水線
final_df = (
pd.read_csv('raw_data.csv', parse_dates=['time'])
.query("status == 'success'")
.assign(
# 在鏈中直接創(chuàng)建新列
revenue = lambda x: x['price'] * x['qty'],
year_month = lambda x: x['time'].dt.to_period('M')
)
.pipe(drop_outliers, col='revenue') # 接入自定義函數(shù)
.groupby('year_month')
.agg(total_rev=('revenue', 'sum'))
.reset_index()
)
7.2 代碼規(guī)范 Checklist
- 禁止使用
inplace=True:它不僅不能節(jié)省內(nèi)存,還會(huì)破壞鏈?zhǔn)骄幊?,且?CoW 機(jī)制下已被逐步廢棄。 - 警惕
object類型:讀取數(shù)據(jù)后,第一時(shí)間將字符串轉(zhuǎn)為string或category,將大整數(shù)降級(jí)為int32。 - 隔離業(yè)務(wù)邏輯:將復(fù)雜的
groupby或清洗邏輯封裝為獨(dú)立的函數(shù),通過pipe調(diào)用,便于單元測試。 - 大表關(guān)聯(lián)先聚合:永遠(yuǎn)不要拿兩張千萬級(jí)的明細(xì)表直接
merge,先在子表groupby聚合到合適的粒度,再進(jìn)行關(guān)聯(lián)。
到此這篇關(guān)于Python Pandas數(shù)據(jù)分析的使用完整教學(xué)的文章就介紹到這了,更多相關(guān)Python Pandas數(shù)據(jù)分析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Python數(shù)據(jù)分析之Matplotlib數(shù)據(jù)可視化
- Python數(shù)據(jù)分析應(yīng)用之Matplotlib數(shù)據(jù)可視化詳情
- Python數(shù)據(jù)分析進(jìn)階之構(gòu)建可復(fù)用的數(shù)據(jù)處理類與模塊化腳本
- Python項(xiàng)目實(shí)戰(zhàn):電商平臺(tái)銷售數(shù)據(jù)分析
- python數(shù)據(jù)分析中的多種圖形繪制示例(折線圖、柱狀圖、餅狀圖、散點(diǎn)圖、熱力圖)
- 使用Python對(duì)MySQL進(jìn)行數(shù)據(jù)分析
- Python對(duì)時(shí)間序列進(jìn)行數(shù)據(jù)分析與可視化的實(shí)戰(zhàn)指南
- Python數(shù)據(jù)分析必備的12種數(shù)據(jù)清洗技術(shù)分享
- Python進(jìn)行數(shù)據(jù)分析的全流程指南
- Python進(jìn)行數(shù)據(jù)分析的5大常見錯(cuò)誤與解決
- Python分析寶馬全球銷售數(shù)據(jù)?實(shí)戰(zhàn)項(xiàng)目教你掌握數(shù)據(jù)清洗與可視化
相關(guān)文章
python安裝后無法打開IDLE?Subprocess?Connection?Error的解決方法
有朋友在安裝了Python之后發(fā)現(xiàn)不能正常使用,就說明安裝過程出了問題,下面這篇文章主要給大家介紹了關(guān)于python安裝后無法打開IDLE?Subprocess?Connection?Error的解決方法,需要的朋友可以參考下2023-01-01
Python數(shù)據(jù)分析之PMI數(shù)據(jù)圖形展示
這篇文章主要介紹了Python數(shù)據(jù)分析之PMI數(shù)據(jù)圖形展示,文章介紹了簡單的python爬蟲,并使用numpy進(jìn)行了簡單的數(shù)據(jù)處理,最終使用?matplotlib?進(jìn)行圖形繪制,實(shí)現(xiàn)了直觀的方式展示制造業(yè)和非制造業(yè)指數(shù)圖形,需要的朋友可以參考一下2022-05-05
python 爬取古詩文存入mysql數(shù)據(jù)庫的方法
這篇文章主要介紹了python 爬取古詩文存入mysql數(shù)據(jù)庫的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01
Python合并2個(gè)字典成1個(gè)新字典的方法(9種)
這篇文章主要介紹了Python合并2個(gè)字典成1個(gè)新字典的方法,本文通過實(shí)例代碼給大家分享9中方法,需要的朋友可以參考下2019-12-12
python實(shí)現(xiàn)比對(duì)美團(tuán)接口返回?cái)?shù)據(jù)和本地mongo數(shù)據(jù)是否一致示例
這篇文章主要介紹了python實(shí)現(xiàn)比對(duì)美團(tuán)接口返回?cái)?shù)據(jù)和本地mongo數(shù)據(jù)是否一致,涉及Python基于requests模塊的數(shù)據(jù)請(qǐng)求與比較運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2019-08-08

