本文详细介绍 Pandas 的进阶主题,包括:
# 基本函数应用
def calculate_bonus(salary, performance):
"""计算奖金
Args:
salary (float): 基本工资
performance (float): 绩效分数 (0-1)
Returns:
float: 奖金金额
"""
return salary * performance * 0.1
# 应用到 DataFrame
df['bonus'] = df.apply(
lambda x: calculate_bonus(x['salary'], x['performance']),
axis=1
)
# 使用 applymap 应用到所有元素
def format_currency(x):
"""格式化货币
Args:
x (float): 金额
Returns:
str: 格式化后的金额
"""
return f"${x:,.2f}"
df = df.applymap(format_currency)
# 使用 transform 保持索引
def normalize_column(x):
"""标准化列
Args:
x (pd.Series): 输入序列
Returns:
pd.Series: 标准化后的序列
"""
return (x - x.mean()) / x.std()
df['normalized_value'] = df.groupby('category')['value'].transform(normalize_column)
# 使用 map 进行值映射
category_map = {
'A': 'High',
'B': 'Medium',
'C': 'Low'
}
df['category_level'] = df['category'].map(category_map)
# 使用 replace 进行值替换
df['status'] = df['status'].replace({
'active': 1,
'inactive': 0,
'pending': -1
})
# 使用 apply 进行复杂映射
def map_complex_value(row):
"""复杂值映射
Args:
row (pd.Series): 行数据
Returns:
str: 映射后的值
"""
if row['age'] < 18:
return 'Minor'
elif row['age'] < 65:
return 'Adult'
else:
return 'Senior'
df['age_group'] = df.apply(map_complex_value, axis=1)
# 使用 numba 优化函数
from numba import jit
@jit(nopython=True)
def calculate_statistics(values):
"""计算统计量
Args:
values (np.array): 数值数组
Returns:
tuple: (均值, 标准差)
"""
mean = 0.0
for x in values:
mean += x
mean /= len(values)
std = 0.0
for x in values:
std += (x - mean) ** 2
std = (std / len(values)) ** 0.5
return mean, std
# 使用向量化操作
def vectorized_calculation(df):
"""向量化计算
Args:
df (pd.DataFrame): 输入数据
Returns:
pd.DataFrame: 计算结果
"""
# 使用 numpy 的向量化操作
df['result'] = np.where(
df['value'] > df['threshold'],
df['value'] * 1.1,
df['value'] * 0.9
)
return df
# 使用并行处理
from multiprocessing import Pool
def parallel_process(df, func, n_cores=4):
"""并行处理
Args:
df (pd.DataFrame): 输入数据
func (function): 处理函数
n_cores (int): 核心数
Returns:
pd.DataFrame: 处理结果
"""
# 分割数据
chunks = np.array_split(df, n_cores)
# 创建进程池
pool = Pool(n_cores)
# 并行处理
results = pool.map(func, chunks)
# 合并结果
return pd.concat(results)
# 创建多级索引
df = pd.DataFrame({
'value': np.random.randn(100),
'category': np.random.choice(['A', 'B', 'C'], 100),
'subcategory': np.random.choice(['X', 'Y', 'Z'], 100)
})
# 设置多级索引
df = df.set_index(['category', 'subcategory'])
# 使用多级索引
# 选择特定类别
df.loc['A']
# 选择特定子类别
df.loc[('A', 'X')]
# 使用 xs 进行交叉选择
df.xs('X', level='subcategory')
# 重置索引
df = df.reset_index()
# 使用 stack 和 unstack
df_stacked = df.stack()
df_unstacked = df.unstack()
# 设置索引
df = df.set_index('date')
# 重置索引
df = df.reset_index()
# 重命名索引
df.index.name = 'date'
df.index = df.index.rename('date')
# 索引排序
df = df.sort_index()
# 索引对齐
df1 = pd.DataFrame({'A': [1, 2, 3]}, index=['a', 'b', 'c'])
df2 = pd.DataFrame({'B': [4, 5, 6]}, index=['b', 'c', 'd'])
df_aligned = df1.align(df2, join='outer')
# 索引转换
df.index = pd.to_datetime(df.index)
# 检查索引是否唯一
is_unique = df.index.is_unique
# 检查索引是否单调
is_monotonic = df.index.is_monotonic
# 检查索引是否已排序
is_sorted = df.index.is_monotonic_increasing
# 优化索引
def optimize_index(df):
"""优化索引
Args:
df (pd.DataFrame): 输入数据
Returns:
pd.DataFrame: 优化后的数据
"""
# 检查索引类型
if isinstance(df.index, pd.DatetimeIndex):
# 确保索引已排序
if not df.index.is_monotonic:
df = df.sort_index()
# 检查索引是否连续
if not df.index.is_monotonic_increasing:
df = df.reindex(pd.date_range(
df.index.min(),
df.index.max(),
freq='D'
))
return df
# 使用示例
df = pd.DataFrame({
'value': np.random.randn(100)
}, index=pd.date_range('2023-01-01', periods=100))
# 优化索引
df = optimize_index(df)
# 导出为 CSV
df.to_csv('output.csv', index=False)
# 导出为 Excel
df.to_excel('output.xlsx', sheet_name='Sheet1', index=False)
# 导出为 JSON
df.to_json('output.json', orient='records')
# 导出为 SQL
from sqlalchemy import create_engine
engine = create_engine('sqlite:///database.db')
df.to_sql('table_name', engine, if_exists='replace')
# 导出为 HTML
df.to_html('output.html')
# 导出为 Markdown
df.to_markdown('output.md')
# 使用 gzip 压缩
df.to_csv('output.csv.gz', compression='gzip', index=False)
# 使用 zip 压缩
df.to_csv('output.csv.zip', compression='zip', index=False)
# 使用 bz2 压缩
df.to_csv('output.csv.bz2', compression='bz2', index=False)
# 使用 xz 压缩
df.to_csv('output.csv.xz', compression='xz', index=False)
# 自定义压缩函数
def compress_data(df, output_file, compression='gzip'):
"""压缩数据
Args:
df (pd.DataFrame): 输入数据
output_file (str): 输出文件路径
compression (str): 压缩方式
"""
df.to_csv(output_file, compression=compression, index=False)
# 批量导出
def batch_export(df, output_dir, chunk_size=10000):
"""批量导出数据
Args:
df (pd.DataFrame): 输入数据
output_dir (str): 输出目录
chunk_size (int): 块大小
"""
# 创建输出目录
import os
os.makedirs(output_dir, exist_ok=True)
# 分块导出
for i, chunk in enumerate(np.array_split(df, len(df) // chunk_size + 1)):
output_file = os.path.join(output_dir, f'chunk_{i}.csv')
chunk.to_csv(output_file, index=False)
# 批量转换格式
def batch_convert(input_dir, output_dir, input_format='csv', output_format='excel'):
"""批量转换格式
Args:
input_dir (str): 输入目录
output_dir (str): 输出目录
input_format (str): 输入格式
output_format (str): 输出格式
"""
# 创建输出目录
import os
os.makedirs(output_dir, exist_ok=True)
# 获取输入文件列表
input_files = [f for f in os.listdir(input_dir) if f.endswith(f'.{input_format}')]
# 转换每个文件
for input_file in input_files:
# 读取输入文件
input_path = os.path.join(input_dir, input_file)
df = pd.read_csv(input_path)
# 生成输出文件名
output_file = os.path.splitext(input_file)[0] + f'.{output_format}'
output_path = os.path.join(output_dir, output_file)
# 导出文件
if output_format == 'excel':
df.to_excel(output_path, index=False)
elif output_format == 'json':
df.to_json(output_path, orient='records')
elif output_format == 'csv':
df.to_csv(output_path, index=False)
进阶主题部分涵盖了:
掌握这些进阶主题对于提升 Pandas 使用水平至关重要,它可以帮助我们:
建议在实际项目中注意: