一、环境约定
python
import numpy as np
import pandas as pd
pd.set_option('display.max_columns', None) # 控制台看全列
pd.set_option('display.width', 180)
二、核心数据结构
| 对象 | 维度 | 轴标签 | 典型用途 | 创建示例 |
|---|---|---|---|---|
| Series | 1D | index | 单列/向量 | s = pd.Series([1,3,5], index=['a','b','c']) |
| DataFrame | 2D | index+columns | 整张表 | df = pd.DataFrame({'x':[1,2],'y':[3,4]}) |
| Index | - | - | 行/列标签 | pd.Index(...) |
三、IO 一行代码
python
df = pd.read_csv('file.csv', encoding='utf-8-sig', parse_dates=['date'])
df.to_parquet('out.parquet', index=False) # 极速读写
# 其余:read_excel / read_sql / read_json / read_html / read_pickle ...
四、快速观察
python
df.head(3) / df.tail(3)
df.info() # 列类型、非空计数
df.describe(include='all').T
df.shape, df.columns, df.index
df.dtypes.value_counts()
五、列(Series)常用操作
python
s = df['col']
s.unique(), s.nunique(), s.value_counts(dropna=False)
s.isna().sum(), s.fillna(0), s.dropna()
s.astype('category'), pd.to_numeric(s, errors='coerce')
s.str.contains('abc', case=False, na=False)
s.dt.year / s.dt.day_name() # 日期列
s.map(dict_map), s.replace({'old': 'new'})
s.clip(lower=0, upper=99)
s.rank(method='dense', ascending=False)
六、行/列 选取(核心 8 招)
- 列名列表:
df[['A','C']] - 切片行:
df[10:20] - 布尔索引:
df[df['age']>=18] - loc 标签:
df.loc[行标签, 列标签] - iloc 位置:
df.iloc[行号, 列号] - query 语法:
df.query('age>=18 & city=="BJ"') - isin:
df[df['city'].isin(['BJ','SH'])] - where/mask:
python
df['new'] = df['old'].where(df['old']>0, 0) # 小于 0 的变 0
七、增删改列
python
df['z'] = df['x']+df['y']
df.assign(z=lambda d:d.x+d.y, # 链式写法
z2=d.x*2)
df.drop(columns=['tmp'], inplace=True)
df.rename(columns={'old':'new'}, inplace=True)
八、缺失值处理套路
python
df.isna().mean().sort_values(ascending=False) # 看缺失率
df.dropna(thresh=df.shape[1]*0.5, inplace=True) # 缺失过半的行整行删
df['age'].fillna(df['age'].median(), inplace=True)
df.fillna(method='ffill').fillna(method='bfill') # 前后向填充
九、重复与异常
python
df.duplicated(subset=['id']).sum()
df.drop_duplicates(subset=['id'], keep='last', inplace=True)
df[(np.abs(stats.zscore(df['amount'])) > 3)] # 3σ 异常
十、分组聚合(split-apply-combine)
python
agg_d = {'salary':'mean', 'age':['max','min']}
df.groupby('dept').agg(agg_d).round(2)
# 多索引列变平:
df_g.columns = ['_'.join(col).strip() for col in df_g.columns.values]
# transform 保持原形状:
df['avg_dept_salary'] = df.groupby('dept')['salary'].transform('mean')
十一、长宽表互转
python
# 长→宽
df_p = df.pivot_table(index='date', columns='code', values='close')
# 宽→长
df_m = df_p.reset_index().melt(id_vars='date', var_name='code', value_name='close')
十二、连接/合并
python
pd.concat([df1, df2], axis=0, ignore_index=True) # 行堆
pd.merge(df_order, df_user, on='uid', how='left', indicator=True)
df.join(df2.set_index('id'), on='id') # 按索引
十三、时间序列
python
pd.date_range('2020-01-01', periods=100, freq='B') # 工作日
df.set_index('date', inplace=True)
df.asfreq('M', method='ffill')
df.shift(1), df.diff(), df.rolling(7).mean()
df.resample('W').agg({'close':'last','volume':'sum'})
十四、加速技巧
- 矢量化:杜绝 for,优先 numpy/pandas 内置
- 分类型:
python
df['cat'] = df['cat'].astype('category') # 省内存 & 提速 groupby
- eval/query:
python
df.eval('profit = revenue - cost', inplace=True)
- 并行:
python
from pandarallel import pandarallel; pandarallel.initialize()
df['new'] = df.col.parallel_apply(func)
- 大文件分块:
python
for chunk in pd.read_csv('big.csv', chunksize=100_000):
process(chunk)
十五、实战小抄
- 生成测试数据:
python
df = pd.util.testing.makeDataFrame().reset_index(drop=True)
- 列名批量清洗:
python
df.columns = df.columns.str.strip().str.lower().str.replace(' ','_')
- 按组 Top-N:
python
df_top = (df.sort_values(['dept','score'], ascending=[True,False])
.groupby('dept').head(3))
- 拆分一列多值:
python
df['tags'].str.split(',', expand=True).stack()
- 快速画趋势:
python
df.set_index('date')['value'].plot(figsize=(10,4))
十六、常见报错速解
| 报错信息 | 快速定位 |
|---|---|
SettingWithCopyWarning |
链式赋值 → 先 df = df.copy() 或一步到位 |
PerformanceWarning: indexing past lexsort depth |
多级索引先 df.sort_index() |
Cannot compare types 'ndarray(dtype=object)' |
列混类型 → astype 统一 |
十七、记忆口诀(一图流)
"选列用中括号,筛选先布尔;
loc 对标签,iloc 对位置;
分组用 agg,保持形状 transform;
长宽 pivot&melt,连接 merge&concat;
缺失 fillna,类别 astype;
速度靠矢量化,实在不快就并行。"