# pandas 快速参考

*DataFrame、数据选择、聚合、合并等核心操作*

> Source: pandas Documentation (pandas.pydata.org) · MIT

## DataFrame

### 创建 DataFrame

```
import pandas as pd
df = pd.DataFrame({
    "name": ["Alice", "Bob", "Carol"],
    "age": [25, 30, 35],
    "score": [88, 92, 79]
})
```

### 数据概览

| Command | Description |
|---------|-------------|
| `df.head(n)` | 前 n 行（默认 5 行） |
| `df.tail(n)` | 后 n 行 |
| `df.shape` | （行数, 列数）元组 |
| `df.dtypes` | 每列的数据类型 |
| `df.info()` | 列类型与非空计数 |
| `df.describe()` | 数值列统计摘要 |
| `df.columns` | 列名 Index |
| `df.index` | 行标签 |

## 读取数据

### 常用读取函数

```
df = pd.read_csv("data.csv")
df = pd.read_excel("data.xlsx")
df = pd.read_json("data.json")
df = pd.read_sql(query, connection)
```

### 写出数据

```
df.to_csv("out.csv", index=False)
df.to_excel("out.xlsx", index=False)
df.to_json("out.json", orient="records")
```

### 读取选项

| Command | Description |
|---------|-------------|
| `sep=";"` | 自定义分隔符 |
| `header=None` | 文件无表头行 |
| `usecols=[0,2]` | 只读指定列 |
| `nrows=100` | 只读前 100 行 |
| `na_values=["N/A"]` | 将该值视为 NaN |

## 数据选取

### 列选取

```
df["name"]              # 单列（Series）
df[["name", "age"]]     # 多列（DataFrame）
df.name                 # 属性访问（简单列名）
```

### 用 loc / iloc 选行

```
df.loc[0]              # 按标签选行
df.loc[0:2, "name"]    # 0-2 行，name 列
df.iloc[0]             # 按位置选行
df.iloc[0:2, 0:2]     # 前 2 行，前 2 列
```

### loc 与 iloc 对比

| Command | Description |
|---------|-------------|
| `df.loc[row, col]` | 按**标签**选取（含右端点） |
| `df.iloc[row, col]` | 按**位置**选取（不含右端点） |
| `df.at[row, col]` | 按标签快速访问单个标量 |
| `df.iat[row, col]` | 按位置快速访问单个标量 |

## 数据过滤

### 布尔过滤

```
df[df["age"] > 25]
df[df["name"].str.contains("li")]
df[(df["age"] > 25) & (df["score"] > 80)]
df[df["name"].isin(["Alice", "Bob"])]
```

### 处理缺失值

```
df.isna().sum()          # 各列 NaN 计数
df.dropna()              # 删除含 NaN 的行
df.fillna(0)             # 用 0 填充 NaN
df["col"].fillna(df["col"].mean())
```

### 排序

```
df.sort_values("age")                # 升序
df.sort_values("age", ascending=False)
df.sort_values(["age", "score"])      # 多列排序
```

## 聚合

### 常用聚合函数

| Command | Description |
|---------|-------------|
| `df["col"].sum()` | 列求和 |
| `df["col"].mean()` | 均值 |
| `df["col"].median()` | 中位数 |
| `df["col"].std()` | 标准差 |
| `df["col"].min() / .max()` | 最小值 / 最大值 |
| `df["col"].count()` | 非空值计数 |
| `df["col"].nunique()` | 唯一值数量 |
| `df["col"].value_counts()` | 各值出现频次 |

### 多指标聚合

```
df.agg({"age": "mean", "score": ["min", "max"]})
df.describe()  # 所有数值列的统计摘要
```

## 分组

### 基础分组

```
df.groupby("dept")["salary"].mean()
df.groupby("dept").agg(
    avg_sal=("salary", "mean"),
    count=("salary", "count")
)
```

### 多键分组

```
df.groupby(["dept", "year"])["sales"].sum()
df.groupby("dept").size()  # 每组行数
```

### transform 与 apply

```
df["z_score"] = df.groupby("dept")["salary"] \
    .transform(lambda x: (x - x.mean()) / x.std())
df.groupby("dept").apply(lambda g: g.nlargest(3, "salary"))
```

## 合并

### merge（SQL 风格 Join）

```
pd.merge(df1, df2, on="id")          # inner join
pd.merge(df1, df2, on="id", how="left")
pd.merge(df1, df2, left_on="uid",
         right_on="user_id")
```

### 连接类型

| Command | Description |
|---------|-------------|
| `how="inner"` | 只保留两表匹配行（默认） |
| `how="left"` | 保留左表全部行，右表无匹配则 NaN |
| `how="right"` | 保留右表全部行 |
| `how="outer"` | 保留两表全部行 |

### 拼接

```
pd.concat([df1, df2])             # 按行堆叠
pd.concat([df1, df2], axis=1)     # 按列并排
pd.concat([df1, df2], ignore_index=True)
```

## 透视表

### pivot_table

```
df.pivot_table(
    values="sales", index="region",
    columns="quarter", aggfunc="sum"
)
```

### 重塑数据

```
df.melt(id_vars=["name"],
        value_vars=["q1", "q2"],
        var_name="quarter", value_name="sales")
```

### 交叉表

```
pd.crosstab(df["dept"], df["gender"])
pd.crosstab(df["dept"], df["gender"],
            normalize="index")  # 行百分比
```

## 时间序列

### 日期时间基础

```
df["date"] = pd.to_datetime(df["date"])
df["year"] = df["date"].dt.year
df["month"] = df["date"].dt.month
df["weekday"] = df["date"].dt.day_name()
```

### 日期范围与重采样

```
pd.date_range("2025-01-01", periods=12, freq="ME")
df.set_index("date").resample("ME")["sales"].sum()
```

### dt 访问器属性

| Command | Description |
|---------|-------------|
| `.dt.year / .dt.month / .dt.day` | 提取日期组件 |
| `.dt.hour / .dt.minute` | 提取时间组件 |
| `.dt.day_name()` | 星期名称（如 Monday） |
| `.dt.days_in_month` | 该月天数 |

## 常用模式

### 重命名列

```
df.rename(columns={"old": "new"})
df.columns = ["a", "b", "c"]  # 替换所有列名
```

### 新增/修改列

```
df["total"] = df["q1"] + df["q2"]
df["grade"] = df["score"].apply(
    lambda x: "A" if x >= 90 else "B"
)
```

### 删除列/行

```
df.drop(columns=["temp"])
df.drop_duplicates(subset=["name"])
df.reset_index(drop=True)
```

### 字符串操作

```
df["name"].str.lower()
df["name"].str.contains("ali", case=False)
df["name"].str.split(" ").str[0]  # 名字
```
