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 数据分析的核心工具,掌握这些技巧可以高效处理各种数据任务。根据具体需求选择合适的方法,平衡代码可读性和性能。









results matching ""

    No results matching ""