Python DataFrame 详细教程
DataFrame 是 Python 数据分析的核心数据结构,主要由 pandas 库提供。以下是 DataFrame 的全面教程。
1. DataFrame 基础
1.1 创建 DataFrame
import pandas as pd
import numpy as np
# 从字典创建
data = {
'姓名': ['张三', '李四', '王五'],
'年龄': [25, 30, 28],
'城市': ['北京', '上海', '广州']
}
df = pd.DataFrame(data)
# 从列表创建
data = [
['张三', 25, '北京'],
['李四', 30, '上海'],
['王五', 28, '广州']
]
df = pd.DataFrame(data, columns=['姓名', '年龄', '城市'])
# 从Numpy数组创建
arr = np.array([
['张三', 25, '北京'],
['李四', 30, '上海'],
['王五', 28, '广州']
])
df = pd.DataFrame(arr, columns=['姓名', '年龄', '城市'])
# 从文件创建
df = pd.read_csv('data.csv') # CSV文件
df = pd.read_excel('data.xlsx') # Excel文件
1.2 查看 DataFrame
print(df.head()) # 查看前5行
print(df.tail(3)) # 查看后3行
print(df.shape) # 查看形状(行数,列数)
print(df.columns) # 查看列名
print(df.index) # 查看索引
print(df.dtypes) # 查看每列数据类型
print(df.info()) # 查看数据摘要
print(df.describe()) # 查看数值列统计信息
2. 数据选择与过滤
2.1 选择列
# 选择单列(返回Series)
ages = df['年龄']
# 选择多列(返回DataFrame)
subset = df[['姓名', '城市']]
# 点表示法(列名不含空格时可用)
city = df.城市
2.2 选择行
# 通过索引标签
row = df.loc[0] # 选择第一行
# 通过位置索引
row = df.iloc[0] # 选择第一行
# 切片选择多行
rows = df[1:3] # 选择第2到第3行
rows = df.iloc[1:3] # 同上
2.3 条件过滤
# 简单条件
young = df[df['年龄'] < 30]
# 多条件组合
bj_young = df[(df['城市'] == '北京') & (df['年龄'] < 30)]
# isin方法
cities = ['北京', '上海']
filtered = df[df['城市'].isin(cities)]
# 字符串方法
start_with_z = df[df['姓名'].str.startswith('张')]
# query方法
result = df.query('年龄 > 25 and 城市 != "北京"')
2.4 高级选择
# 同时选择行和列
subset = df.loc[df['年龄'] > 25, ['姓名', '城市']]
# 使用iloc按位置选择
subset = df.iloc[1:3, 0:2] # 第2-3行,第1-2列
# 使用at/iat快速访问标量
value = df.at[0, '姓名'] # 张三
value = df.iat[0, 0] # 张三
3. 数据操作
3.1 添加/删除列
# 添加新列
df['年薪'] = df['年龄'] * 10000
# 使用assign(不修改原DataFrame)
df = df.assign(月薪=lambda x: x['年薪'] / 12)
# 删除列
df = df.drop('月薪', axis=1) # axis=1表示列
df.drop('月薪', axis=1, inplace=True) # 原地修改
# 重命名列
df = df.rename(columns={'年薪': '年收入'})
3.2 处理缺失值
# 检测缺失值
print(df.isnull()) # 布尔DataFrame
print(df.isnull().sum()) # 每列缺失值计数
# 删除缺失值
df_clean = df.dropna() # 删除包含缺失值的行
df_clean = df.dropna(axis=1) # 删除包含缺失值的列
df_clean = df.dropna(thresh=2) # 至少2个非NA值才保留
# 填充缺失值
df_filled = df.fillna(0) # 用0填充
df_filled = df.fillna({'年龄': df['年龄'].mean()}) # 用均值填充年龄列
df_filled = df.fillna(method='ffill') # 用前一个值填充
3.3 数据排序
# 按列排序
df_sorted = df.sort_values('年龄') # 升序
df_sorted = df.sort_values('年龄', ascending=False) # 降序
# 多列排序
df_sorted = df.sort_values(['城市', '年龄'], ascending=[True, False])
# 按索引排序
df_sorted = df.sort_index(ascending=False)
3.4 数据分组
# 基本分组
grouped = df.groupby('城市')
# 聚合操作
city_stats = grouped.agg({
'年龄': ['mean', 'min', 'max', 'count'],
'年薪': 'sum'
})
# 多列分组
multi_group = df.groupby(['城市', df['年龄'] > 25])
# 应用自定义函数
def normalize(x):
return (x - x.mean()) / x.std()
normalized = grouped.transform(normalize)
4. 数据清洗与转换
4.1 数据类型转换
# 查看数据类型
print(df.dtypes)
# 转换数据类型
df['年龄'] = df['年龄'].astype('float64')
# 转换为分类数据
df['城市'] = df['城市'].astype('category')
# 转换为日期
df['日期'] = pd.to_datetime(df['日期列'])
4.2 字符串操作
# 字符串方法
df['姓名'] = df['姓名'].str.upper() # 转为大写
df['姓名'] = df['姓名'].str.strip() # 去除空格
df['姓名长度'] = df['姓名'].str.len() # 计算长度
# 正则表达式
df['区号'] = df['电话'].str.extract(r'(\d{3})') # 提取前3位数字
# 拆分列
df[['姓', '名']] = df['姓名'].str.split(' ', expand=True)
4.3 重复数据处理
# 检测重复行
print(df.duplicated()) # 布尔Series
print(df.duplicated().sum()) # 重复行数
# 删除重复行
df_unique = df.drop_duplicates()
df_unique = df.drop_duplicates(subset=['姓名']) # 根据姓名去重
5. 数据合并与连接
5.1 合并DataFrame
# 上下合并(相同列名)
df_combined = pd.concat([df1, df2], axis=0)
# 左右合并(相同行索引)
df_combined = pd.concat([df1, df2], axis=1)
# 使用merge(类似SQL JOIN)
merged = pd.merge(df1, df2, on='key') # 内连接
merged = pd.merge(df1, df2, on='key', how='left') # 左连接
merged = pd.merge(df1, df2, on='key', how='outer') # 全外连接
# 使用join(基于索引合并)
joined = df1.join(df2, how='inner')
5.2 数据透视表
# 创建透视表
pivot = pd.pivot_table(df,
values='年薪',
index='城市',
columns='性别',
aggfunc=np.mean,
fill_value=0)
# 多级透视
pivot = pd.pivot_table(df,
values=['年薪', '年龄'],
index=['城市', '教育程度'],
aggfunc={'年薪': np.mean, '年龄': [np.min, np.max]})
6. 时间序列处理
6.1 时间索引
# 设置时间索引
df['日期'] = pd.to_datetime(df['日期'])
df = df.set_index('日期')
# 时间范围选择
df.loc['2023-01'] # 选择2023年1月数据
df.loc['2023-01':'2023-03'] # 选择2023年1月至3月数据
# 重采样
monthly = df.resample('M').mean() # 按月重采样求均值
6.2 时间操作
# 提取时间组件
df['年份'] = df.index.year
df['月份'] = df.index.month
df['星期'] = df.index.dayofweek # 周一=0, 周日=6
# 时间差计算
df['时长'] = df['结束时间'] - df['开始时间']
df['时长小时'] = df['时长'].dt.total_seconds() / 3600
# 时间偏移
df['下个月'] = df.index + pd.DateOffset(months=1)
7. 性能优化技巧
7.1 向量化操作
# 避免循环,使用向量化操作
df['奖金'] = df['年薪'] * 0.1 # 好
df['奖金'] = [x * 0.1 for x in df['年薪']] # 差(慢)
7.2 使用高效数据类型
# 减少内存使用
df['城市'] = df['城市'].astype('category')
df['年龄'] = pd.to_numeric(df['年龄'], downcast='integer')
7.3 大数据处理
# 分块处理大文件
chunksize = 10000
for chunk in pd.read_csv('large_file.csv', chunksize=chunksize):
process(chunk)
# 使用Dask处理超大数据
import dask.dataframe as dd
ddf = dd.read_csv('very_large_file.csv')
result = ddf.groupby('城市').年龄.mean().compute()
8. 可视化集成
import matplotlib.pyplot as plt
# 简单绘图
df.plot(x='日期', y='销售额', kind='line')
plt.show()
# 多子图
df.plot(subplots=True, figsize=(10, 8))
plt.tight_layout()
plt.show()
# 使用Seaborn
import seaborn as sns
sns.boxplot(x='城市', y='年龄', data=df)
plt.show()
9. 输入输出
9.1 读取数据
# 从CSV
df = pd.read_csv('data.csv', encoding='utf-8', parse_dates=['日期'])
# 从Excel
df = pd.read_excel('data.xlsx', sheet_name='Sheet1')
# 从SQL
import sqlite3
conn = sqlite3.connect('database.db')
df = pd.read_sql('SELECT * FROM table', conn)
# 从JSON
df = pd.read_json('data.json', orient='records')
9.2 保存数据
# 保存为CSV
df.to_csv('output.csv', index=False, encoding='utf-8')
# 保存为Excel
df.to_excel('output.xlsx', sheet_name='数据', index=False)
# 保存为SQL
df.to_sql('table_name', conn, if_exists='replace', index=False)
# 保存为JSON
df.to_json('output.json', orient='records')
10. 高级技巧
10.1 自定义函数应用
# 应用函数到列
df['标准化年龄'] = df['年龄'].apply(lambda x: (x - x.mean()) / x.std())
# 应用函数到行
df['简介'] = df.apply(lambda row: f"{row['姓名']}来自{row['城市']}", axis=1)
# 向量化函数
@np.vectorize
def categorize_age(age):
return '青年' if age < 30 else '中年'
df['年龄段'] = categorize_age(df['年龄'])
10.2 多索引操作
# 创建多索引
df = df.set_index(['城市', '姓名'])
# 多索引选择
df.loc[('北京', '张三')] # 选择北京张三的数据
df.xs('北京', level='城市') # 选择所有北京的数据
# 重置索引
df = df.reset_index()
10.3 内存优化
# 查看内存使用
print(df.memory_usage(deep=True))
# 优化数据类型
df['年龄'] = pd.to_numeric(df['年龄'], downcast='integer')
df['城市'] = df['城市'].astype('category')
# 使用稀疏数据结构
df = df.astype(pd.SparseDtype())
DataFrame 是 Python 数据分析的核心工具,掌握这些技巧可以高效处理各种数据任务。根据具体需求选择合适的方法,平衡代码可读性和性能。