# Pandas学习笔记

Canonical: https://www.mirstar.net/2025/12/26/pandas-learning-journal/
Author: onlymatt
Published: 2025-12-26T10:22:16.000Z
Updated: 2026-10-21T11:21:55.773Z
Categories: Programming, Python
Tags: pandas, Data Analysis

# pandas DataFrame 使用大全

## 一、**创建 DataFrame**

### 1. 从字典创建
```python
import pandas as pd
import numpy as np

# 基本字典创建
data = {'A': [1, 2, 3], 'B': [4, 5, 6], 'C': [7, 8, 9]}
df = pd.DataFrame(data)

# 指定行索引
df = pd.DataFrame(data, index=['row1', 'row2', 'row3'])

# 从字典列表创建（每条字典为一列）
data = [{'A': 1, 'B': 2}, {'A': 3, 'B': 4}]
df = pd.DataFrame(data)
```

### 2. 从列表创建
```python
# 列表的列表（每个子列表为一行）
data = [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
df = pd.DataFrame(data, columns=['A', 'B', 'C'])

# 元组的列表
data = [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
df = pd.DataFrame(data, columns=['A', 'B', 'C'])
```

### 3. 从 Series 创建
```python
s1 = pd.Series([1, 2, 3], name='A')
s2 = pd.Series([4, 5, 6], name='B')
df = pd.concat([s1, s2], axis=1)
```

### 4. 从 NumPy 数组创建
```python
arr = np.array([[1, 4], [2, 5], [3, 6]])
df = pd.DataFrame(arr, columns=['A', 'B'])
```

### 5. 特殊创建方法
```python
# 创建空 DataFrame
df_empty = pd.DataFrame()

# 创建重复值的 DataFrame
df_repeat = pd.DataFrame(np.repeat([[1, 2]], 3, axis=0), columns=['A', 'B'])

# 创建随机数据的 DataFrame
df_random = pd.DataFrame(np.random.rand(3, 2), columns=['A', 'B'])

# 创建日期范围作为索引
df_date = pd.DataFrame(
    {'A': [1, 2, 3]},
    index=pd.date_range('2024-01-01', periods=3)
)
```

## 二、**访问数据**

### 1. 基本查看
```python
df.head(2)      # 查看前2行
df.tail(2)      # 查看后2行
df.sample(2)    # 随机查看2行
df.shape        # 形状 (行数, 列数)
df.columns      # 列名列表
df.index        # 索引
df.dtypes       # 每列数据类型
df.info()       # 详细信息
df.describe()   # 统计描述
```

### 2. 选择列
```python
# 选择单列（返回Series）
df['A']
df.A  # 仅当列名是有效Python标识符时可用

# 选择多列（返回DataFrame）
df[['A', 'B']]

# 选择列切片
df.loc[:, 'A':'C']  # 按标签
df.iloc[:, 0:2]     # 按位置
```

### 3. 选择行
```python
# 按标签选择
df.loc['row1']          # 单行
df.loc[['row1', 'row3']]  # 多行
df.loc['row1':'row3']   # 行切片（包含结束）

# 按位置选择
df.iloc[0]             # 单行
df.iloc[[0, 2]]        # 多行
df.iloc[0:3]           # 行切片（不包含结束）
df.iloc[-1]            # 最后一行

# 按条件选择
df[df['A'] > 2]                        # 单条件
df[(df['A'] > 1) & (df['B'] < 6)]      # 多条件
df[df['A'].isin([1, 3])]               # 在列表中
df[~df['A'].isin([1, 3])]              # 不在列表中
df[df['A'].between(1, 3)]              # 在范围内
df[df['A'].str.contains('text')]       # 字符串包含（字符串列）
```

### 4. 同时选择行和列
```python
# loc：基于标签
df.loc['row1', 'A']                # 单个值
df.loc[['row1', 'row2'], ['A', 'B']]  # 多行多列
df.loc['row1':'row3', 'A':'C']     # 行和列切片

# iloc：基于位置
df.iloc[0, 0]                      # 单个值
df.iloc[[0, 2], [0, 1]]            # 多行多列
df.iloc[0:3, 0:2]                  # 行和列切片

# 混合使用（ix已弃用）
df.loc[df['A'] > 1, ['B', 'C']]    # 条件行，指定列
```

### 5. 使用 query 方法
```python
df.query('A > 1')
df.query('A > 1 and B < 6')
df.query('A in [1, 3]')
df.query('@variable_name > A')  # 使用外部变量
```

## 三、**删除数据**

### 1. 删除行
```python
# 按索引删除
df.drop([0, 2])                    # 删除索引为0和2的行
df.drop(index=[0, 2])              # 明确指定删除行
df.drop(['row1', 'row2'])          # 按标签名删除

# 按条件删除
df.drop(df[df['A'] < 2].index)     # 删除A<2的行
df = df[df['A'] >= 2]              # 保留A>=2的行（更常用）

# 删除重复行
df.drop_duplicates()               # 删除完全重复的行
df.drop_duplicates(subset=['A'])   # 基于A列删除重复
df.drop_duplicates(keep='last')    # 保留最后出现的重复

# 删除缺失行
df.dropna()                        # 删除包含NaN的行
df.dropna(subset=['A'])            # 删除A列为NaN的行
df.dropna(thresh=2)                # 至少保留2个非NaN值
```

### 2. 删除列
```python
df.drop('A', axis=1)                # 删除单列
df.drop(['A', 'B'], axis=1)         # 删除多列
df.drop(columns=['A', 'B'])         # 明确指定删除列

# 按条件删除列
df.dropna(axis=1)                   # 删除包含NaN的列
df.loc[:, df.columns != 'A']        # 使用loc保留其他列

# 删除所有为NaN的列
df.dropna(axis=1, how='all')

# 删除特定数据类型的列
df.select_dtypes(exclude=['object'])  # 选择非对象类型，排除字符串列
```

### 3. 重置索引
```python
df.reset_index(drop=True)           # 重置索引并丢弃原索引
df.reset_index()                    # 重置索引，原索引变为列
```

## 四、**修改数据**

### 1. 修改列名
```python
df.rename(columns={'A': 'new_A', 'B': 'new_B'})  # 部分重命名
df.columns = ['new_A', 'new_B', 'new_C']         # 全部重命名
df.columns = df.columns.str.upper()              # 改为大写
df.columns = df.columns.str.replace('_', ' ')    # 替换字符
```

### 2. 修改行索引
```python
df.index = ['row1', 'row2', 'row3']  # 完全替换
df.rename(index={0: 'row1', 1: 'row2'})  # 部分重命名
df.set_index('A')                     # 将A列设为索引
df.reset_index()                      # 重置索引
```

### 3. 修改值
```python
# 修改单个值
df.at[0, 'A'] = 10      # 按标签（最快）
df.iat[0, 0] = 10       # 按位置

# 修改整列
df['A'] = [10, 20, 30]
df['A'] = df['A'] * 2
df['A'] = df['A'].apply(lambda x: x**2)

# 条件修改
df.loc[df['A'] > 2, 'B'] = 99
df['C'] = np.where(df['A'] > 2, 'high', 'low')

# 使用replace
df.replace(2, 20)                      # 将2替换为20
df.replace({1: 10, 3: 30})             # 字典替换
df.replace({'A': {1: 10, 3: 30}})     # 指定列替换
df.replace('[a-z]', 'X', regex=True)  # 正则替换
```

### 4. 添加列
```python
# 直接赋值
df['new_col'] = [1, 2, 3]
df['new_col'] = df['A'] + df['B']

# 使用assign（返回新DataFrame）
df = df.assign(new_col = df['A'] + df['B'],
               another_col = lambda x: x['A'] * 2)

# 插入列到指定位置
df.insert(1, 'new_col', [1, 2, 3])  # 在第1列位置插入

# 使用条件判断
df['category'] = np.where(df['A'] > 2, 'high', 'low')

# 使用apply
df['squared'] = df['A'].apply(lambda x: x**2)
```

### 5. 添加行
```python
# 使用loc
df.loc[len(df)] = [4, 7, 10]  # 添加新行

# 使用append（已弃用，建议用concat）
new_row = pd.DataFrame({'A': [4], 'B': [7], 'C': [10]})
df = pd.concat([df, new_row], ignore_index=True)

# 从字典添加
df = df.append({'A': 4, 'B': 7, 'C': 10}, ignore_index=True)  # 已弃用
```

### 6. 数据类型转换
```python
df['A'] = df['A'].astype('float')
df = df.astype({'A': 'int32', 'B': 'str'})

# 转换日期
df['date_col'] = pd.to_datetime(df['date_str'])
```

## 五、**数据操作**

### 1. 排序
```python
df.sort_values('A')                     # 按A列升序
df.sort_values('A', ascending=False)    # 降序
df.sort_values(['A', 'B'])              # 多列排序
df.sort_index()                         # 按索引排序
```

### 2. 分组聚合
```python
# 基本分组
df.groupby('A').sum()
df.groupby('A').agg({'B': 'sum', 'C': 'mean'})
df.groupby('A').agg(sum_B=('B', 'sum'), mean_C=('C', 'mean'))

# 多级分组
df.groupby(['A', 'B']).mean()

# 使用transform（保持原形状）
df['group_mean'] = df.groupby('A')['B'].transform('mean')
```

### 3. 合并连接
```python
# concat（拼接）
pd.concat([df1, df2], axis=0)  # 纵向拼接
pd.concat([df1, df2], axis=1)  # 横向拼接

# merge（类似SQL JOIN）
pd.merge(df1, df2, on='key')               # 内连接
pd.merge(df1, df2, on='key', how='left')   # 左连接
pd.merge(df1, df2, left_on='key1', right_on='key2')  # 不同列名

# join（按索引连接）
df1.join(df2, how='left')
```

### 4. 数据透视
```python
# 透视表
df.pivot_table(values='C', index='A', columns='B', aggfunc='mean')

# 交叉表
pd.crosstab(df['A'], df['B'])

# 数据重塑
df.pivot(index='A', columns='B', values='C')  # 长变宽
df.melt(id_vars=['A'], value_vars=['B', 'C']) # 宽变长
```

### 5. 缺失值处理
```python
# 检查缺失值
df.isnull()
df.isnull().sum()

# 填充缺失值
df.fillna(0)                          # 用0填充
df.fillna({'A': 0, 'B': df['B'].mean()})  # 不同列不同填充
df.fillna(method='ffill')             # 前向填充
df.fillna(method='bfill')             # 后向填充
df.interpolate()                      # 插值填充

# 删除缺失值（见删除部分）
```

### 6. 重复值处理
```python
df.duplicated()                       # 检查重复行
df.duplicated(subset=['A', 'B'])      # 检查指定列重复
df.drop_duplicates()                  # 删除重复
```

## 六、**常用技巧**

### 1. 链式操作
```python
(df.query('A > 1')
   .sort_values('B')
   .assign(new_col=lambda x: x['A'] * 2)
   .reset_index(drop=True))
```

### 2. 矢量化操作
```python
# 避免使用apply，尽量使用矢量化操作
df['result'] = df['A'] + df['B']  # 推荐
df['result'] = df.apply(lambda row: row['A'] + row['B'], axis=1)  # 不推荐
```

### 3. 内存优化
```python
# 查看内存使用
df.memory_usage(deep=True)

# 减少内存使用
df['A'] = df['A'].astype('int32')  # 使用更小的数据类型
```

### 4. 性能优化
```python
# 使用query提高查询性能（特别是大数据集）
df.query('A > 1 and B < 5')

# 使用类别数据类型提高字符串性能
df['category_col'] = df['category_col'].astype('category')
```

## 七、**保存和加载**

```python
# 保存
df.to_csv('data.csv', index=False)
df.to_excel('data.xlsx', index=False)
df.to_json('data.json')
df.to_pickle('data.pkl')  # 二进制格式，保存所有信息

# 读取
df = pd.read_csv('data.csv')
df = pd.read_excel('data.xlsx')
df = pd.read_json('data.json')
df = pd.read_pickle('data.pkl')
```

1. **使用 `loc` 和 `iloc`** 进行明确的索引访问
2. **避免链式索引**（如 `df['A'][0] = 1`），使用 `df.loc[0, 'A'] = 1`
3. **尽量使用向量化操作**而非循环或apply
4. **注意inplace参数**，大多数操作默认返回新DataFrame
5. **及时释放内存**，处理大数据时注意内存管理
6. **使用query进行复杂筛选**，代码更简洁
7. **保存中间结果**，避免重复计算
