Pandas数据处理精通教程:从数据类型转换到高级分析

Pandas数据处理精通教程:从数据类型转换到高级分析

一、Pandas数据结构与数据类型转换

1.1 Pandas核心数据结构

Pandas提供两种主要数据结构:Series(一维标记数组)和DataFrame(二维表格型数据结构)。

1
2
3
4
5
6
7
8
9
10
11
import pandas as pd
import numpy as np

# 创建DataFrame示例
data = {
'Name': ['Tom', 'Jack', 'Lily'],
'Age': [28, 24, 22],
'City': ['Beijing', 'Shanghai', 'Shenzhen']
}
df = pd.DataFrame(data)
print(df.dtypes)

1.2 查看数据类型

使用dtypes属性查看DataFrame中各列的数据类型:

1
2
3
4
5
# 查看数据类型
print(df.dtypes)

# 查看单列数据类型
print(df['Age'].dtype)

1.3 数据类型转换方法

Pandas提供了多种数据类型转换方法:

使用astype()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
# 创建示例数据
df = pd.DataFrame({
'A': [1, 2, 3],
'B': ['4', '5', '6'],
'C': [1.1, 2.2, 3.3]
})

# 转换数据类型
df['A'] = df['A'].astype('float32') # 整型转浮点型
df['B'] = df['B'].astype('int64') # 字符串转整型
df['C'] = df['C'].astype('int32') # 浮点型转整型

print(df.dtypes)

批量转换数据类型

1
2
3
# 批量转换数值列为float类型
df_numeric = df.select_dtypes(include=[np.number])
df[df_numeric.columns] = df_numeric.astype(float)

特殊数据类型转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
data = {
'Date': ['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04', '2024-01-05'],
'Category': ['A', 'B', 'A', 'B', 'C'],
'Flag': ['True', 'False', 'True', 'False', 'True']
}
df = pd.DataFrame(data)

# 日期时间转换
df['Date'] = pd.to_datetime(df['Date'])

# 分类数据转换
df['Category'] = df['Category'].astype('category')

# 布尔类型转换
df['Flag'] = df['Flag'].astype(bool)

print(df.dtypes)

智能类型推断

1
2
3
# 自动推断合适的数据类型
df_converted = df.convert_dtypes()
print(df_converted.dtypes)

表:Pandas常用数据类型对照表

数据类型 描述 适用场景
int8/int16/int32/int64 整型数据 数值计算、索引
float32/float64 浮点型数据 科学计算、统计分析
object 字符串或混合类型 文本数据
bool 布尔类型 标志位、条件判断
datetime64[ns] 日期时间 时间序列分析
category 分类数据 有限取值的文本数据
string 字符串类型 文本处理

二、缺失值处理技术

2.1 检测缺失值

Pandas使用NaN(Not a Number)表示缺失值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 创建包含缺失值的示例数据
df = pd.DataFrame({
'A': [1, 2, np.nan, 4],
'B': [5, np.nan, np.nan, 8],
'C': [10, 11, 12, np.nan]
})

# 检测缺失值
print("缺失值检测结果:")
print(df.isnull())

print("\n每列缺失值数量:")
print(df.isnull().sum())

print("\n缺失值比例:")
print(df.isnull().sum() / len(df))

2.2 删除缺失值

根据具体情况删除包含缺失值的行或列:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 删除包含缺失值的行
df_dropped_rows = df.dropna()
print("删除缺失行后的形状:", df_dropped_rows.shape)

# 删除包含缺失值的列
df_dropped_cols = df.dropna(axis=1)
print("删除缺失列后的形状:", df_dropped_cols.shape)

# 只删除全部为缺失值的行
df_dropped_all = df.dropna(how='all')
print("删除全缺失行后的形状:", df_dropped_all.shape)

# 删除缺失值达到一定数量的行
df_dropped_thresh = df.dropna(thresh=2) # 至少保留2个非空值
print("阈值删除后的形状:", df_dropped_thresh.shape)

2.3 填充缺失值

简单填充方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 用固定值填充
df_filled_zero = df.fillna(0)
print("用0填充的结果:")
print(df_filled_zero)

# 用前向填充(使用前面的值)
df_filled_ffill = df.fillna(method='ffill')
print("前向填充的结果:")
print(df_filled_ffill)

# 用后向填充(使用后面的值)
df_filled_bfill = df.fillna(method='bfill')
print("后向填充的结果:")
print(df_filled_bfill)

# 限制填充数量
df_filled_limit = df.fillna(method='ffill', limit=1)
print("限制填充数量的结果:")
print(df_filled_limit)

统计值填充

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 用均值填充
df_filled_mean = df.fillna(df.mean())
print("均值填充的结果:")
print(df_filled_mean)

# 用中位数填充
df_filled_median = df.fillna(df.median())
print("中位数填充的结果:")
print(df_filled_median)

# 用众数填充(适用于分类数据)
df_cat = pd.DataFrame({'Category': ['A', 'B', np.nan, 'A', 'B', 'B']})
mode_value = df_cat['Category'].mode()[0]
df_cat_filled = df_cat.fillna(mode_value)
print("众数填充的结果:")
print(df_cat_filled)

插值法填充

插值法可以提供更加精确的缺失值估计:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 创建时间序列数据
dates = pd.date_range('2024-01-01', periods=6)
ts_data = pd.Series([1, np.nan, np.nan, 4, 5, np.nan], index=dates)

# 线性插值
ts_linear = ts_data.interpolate(method='linear')
print("线性插值结果:")
print(ts_linear)

# 多项式插值(二次)
ts_poly = ts_data.interpolate(method='polynomial', order=2)
print("多项式插值结果:")
print(ts_poly)

# 时间索引插值,根据索引之间的实际时间间隔来计算。
ts_time = ts_data.interpolate(method='time')
print("时间插值结果:")
print(ts_time)

2.4 高级缺失值处理技巧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 对不同列使用不同的填充策略
def custom_fill(series):
if series.name == 'A':
return series.fillna(series.mean())
elif series.name == 'B':
return series.fillna(series.median())
else:
return series.fillna(0)

df_custom = df.apply(custom_fill)
print("自定义填充结果:")
print(df_custom)

# 使用字典指定每列的填充值
fill_values = {'A': df['A'].mean(), 'B': 0, 'C': df['C'].median()}
df_dict_fill = df.fillna(fill_values)
print("字典填充结果:")
print(df_dict_fill)

表:缺失值处理策略选择指南

场景 推荐方法 优点 缺点
缺失值较少 删除缺失值 简单直接 可能损失信息
数值型数据,分布均匀 均值填充 保持均值不变 低估方差
数值型数据,存在异常值 中位数填充 抗异常值干扰 忽略数据分布
时间序列数据 插值法填充 保持趋势和模式 对非线性关系敏感
分类数据 众数填充 保持类别平衡 忽略类别关系
数据有自相关性 前向/后向填充 保持顺序关系 可能传播误差

三、异常值检测与处理

3.1 异常值的定义与影响

异常值(Outlier)是指与其他数据点相比显著偏离的数据点,可能由测量误差、数据录入错误或实际极端值引起。异常值会对统计分析结果产生显著影响。

3.2 统计方法检测异常值

Z-score法

Z-score衡量数据点与均值的偏离程度:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def detect_outliers_zscore(data, threshold=3):
"""
使用Z-score方法检测异常值
"""
z_scores = np.abs((data - data.mean()) / data.std())
outliers = data[z_scores > threshold]
return outliers

# 创建包含异常值的示例数据
np.random.seed(42)
normal_data = np.random.normal(50, 10, 100)
outlier_data = np.array([120, 130, -30]) # 添加异常值
combined_data = np.concatenate([normal_data, outlier_data])
df = pd.DataFrame({'Value': combined_data})

# 检测异常值
outliers_zscore = detect_outliers_zscore(df['Value'])
print("Z-score检测到的异常值:")
print(outliers_zscore)

IQR法(四分位距法)

IQR法是箱线图检测异常值的原理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def detect_outliers_iqr(data):
"""
使用IQR方法检测异常值
"""
Q1 = data.quantile(0.25)
Q3 = data.quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = data[(data < lower_bound) | (data > upper_bound)]
return outliers, lower_bound, upper_bound

# 检测异常值
outliers_iqr, lower_bound, upper_bound = detect_outliers_iqr(df['Value'])
print("IQR检测到的异常值:")
print(outliers_iqr)
print(f"正常值范围: [{lower_bound:.2f}, {upper_bound:.2f}]")

3.3 可视化异常值检测

箱线图法

1
2
3
4
5
6
7
8
9
10
import matplotlib.pyplot as plt

# 绘制箱线图检测异常值
plt.figure(figsize=(10, 6))
plt.subplot(1, 2, 1)
df['Value'].plot(kind='box', title='箱线图检测异常值')
plt.subplot(1, 2, 2)
df['Value'].plot(kind='hist', title='数据分布直方图', bins=30)
plt.tight_layout()
plt.show()

3.4 机器学习方法检测异常值

孤立森林(Isolation Forest)

核心思想:

异常点(Outliers)是少数的、与大多数数据点特征不同的观测值。因此,它们比正常数据点更容易被 “孤立” 出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from sklearn.ensemble import IsolationForest

# 准备数据
X = df[['Value']]

# 训练孤立森林模型
clf = IsolationForest(contamination=0.1, random_state=42)
clf.fit(X)

# 预测异常值
pred = clf.predict(X)
df['IsOutlier'] = pred
outliers_iso = df[df['IsOutlier'] == -1]['Value']

print("孤立森林检测到的异常值:")
print(outliers_iso)

局部异常因子(LOF)

LOF 核心思想:一个异常点周围的密度通常比它的邻居们要低得多。

1
2
3
4
5
6
7
8
9
10
11
from sklearn.neighbors import LocalOutlierFactor

# 训练LOF模型
lof = LocalOutlierFactor(n_neighbors=20, contamination=0.1)
y_pred = lof.fit_predict(X)

df['LOF_Outlier'] = y_pred
outliers_lof = df[df['LOF_Outlier'] == -1]['Value']

print("LOF检测到的异常值:")
print(outliers_lof)

3.5 异常值处理方法

删除异常值

1
2
3
4
# 删除异常值
df_cleaned = df[df['IsOutlier'] != -1].copy()
print(f"原始数据形状: {df.shape}")
print(f"清理后数据形状: {df_cleaned.shape}")

替换异常值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 缩尾处理(Winsorizing)
def winsorize_data(data, lower_limit=0.05, upper_limit=0.95):
lower = data.quantile(lower_limit)
upper = data.quantile(upper_limit)
return data.clip(lower=lower, upper=upper)

df['Value_Winsorized'] = winsorize_data(df['Value'])
print("缩尾处理后的数据描述:")
print(df['Value_Winsorized'].describe())

# 用统计值替换异常值
def replace_outliers_with_stats(data, method='median'):
"""用统计值替换异常值"""
Q1 = data.quantile(0.25)
Q3 = data.quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

if method == 'median':
replacement = data.median()
elif method == 'mean':
replacement = data.mean()
else:
replacement = method

cleaned_data = data.copy()
cleaned_data[(data < lower_bound) | (data > upper_bound)] = replacement
return cleaned_data

df['Value_Replaced'] = replace_outliers_with_stats(df['Value'], 'median')

异常值分析报告

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def generate_outlier_report(data):
"""生成异常值分析报告"""
# 检测异常值
outliers, lower_bound, upper_bound = detect_outliers_iqr(data)

report = {
'total_data_points': len(data),
'outlier_count': len(outliers),
'outlier_percentage': len(outliers) / len(data) * 100,
'lower_bound': lower_bound,
'upper_bound': upper_bound,
'outliers_values': outliers.values,
'data_min': data.min(),
'data_max': data.max(),
'data_mean': data.mean(),
'data_median': data.median()
}

return report

# 生成异常值报告
outlier_report = generate_outlier_report(df['Value'])
print("异常值分析报告:")
for key, value in outlier_report.items():
if key != 'outliers_values':
print(f"{key}: {value}")

表:异常值处理方法比较

方法 适用场景 优点 缺点
删除法 异常值较少且明显错误 简单直接 可能损失有用信息
统计值替换 需要保留样本量 保持数据完整性 可能扭曲分布
缩尾处理 保留极端值但限制影响 保留数据趋势 需要选择合适分位数
插值法 时间序列数据 保持数据连续性 对模式敏感
分箱处理 数值型数据 减少异常值影响 可能丢失细节

四、GroupBy分组聚合高级用法

4.1 基础分组操作

GroupBy是Pandas中强大的数据分组工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 创建示例数据
sales_data = pd.DataFrame({
'Region': ['North', 'South', 'East', 'West', 'North', 'South', 'East', 'West'],
'Product': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B'],
'Sales': [100, 120, 90, 110, 150, 130, 140, 160],
'Profit': [20, 25, 18, 22, 30, 28, 35, 32]
})

print("原始数据:")
print(sales_data)

# 基本分组操作
grouped = sales_data.groupby('Region')
print("\n按地区分组后的组别:")
print(grouped.groups)

# 查看分组统计
print("\n各区域销售统计:")
print(grouped['Sales'].describe())

4.2 单列分组与聚合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 单列分组聚合
region_sales = sales_data.groupby('Region')['Sales'].sum()
print("各区域总销售额:")
print(region_sales)

# 多聚合函数
region_stats = sales_data.groupby('Region')['Sales'].agg(['sum', 'mean', 'std', 'count'])
print("\n各区域销售多维度统计:")
print(region_stats)

# 自定义聚合函数
def range_function(x):
return x.max() - x.min()

custom_agg = sales_data.groupby('Region')['Sales'].agg(['sum', range_function])
print("\n自定义聚合结果:")
print(custom_agg)

4.3 多列分组与高级聚合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 多列分组
multi_grouped = sales_data.groupby(['Region', 'Product'])
multi_sales = multi_grouped['Sales'].sum()
print("按地区和产品分组的总销售额:")
print(multi_sales)

# 多列多指标聚合
detailed_stats = sales_data.groupby(['Region', 'Product']).agg({
'Sales': ['sum', 'mean', 'max'],
'Profit': ['sum', 'mean', 'std']
})
print("\n详细统计信息:")
print(detailed_stats)

# 重命名聚合结果列
renamed_stats = sales_data.groupby(['Region', 'Product']).agg(
total_sales=('Sales', 'sum'),
avg_sales=('Sales', 'mean'),
max_profit=('Profit', 'max'),
profit_std=('Profit', 'std')
)
print("\n重命名后的统计结果:")
print(renamed_stats)

4.4 分组转换与过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 分组转换(标准化数据)
def z_score_normalize(x):
return (x - x.mean()) / x.std()

sales_data['Sales_ZScore'] = sales_data.groupby('Region')['Sales'].transform(z_score_normalize)
print("分组标准化后的销售数据:")
print(sales_data[['Region', 'Sales', 'Sales_ZScore']])

# 分组过滤
def filter_small_groups(x):
return x['Sales'].sum() > 200

filtered_groups = sales_data.groupby('Region').filter(filter_small_groups)
print("\n过滤后的数据(只保留总销售额>200的区域):")
print(filtered_groups)

# 分组排序
def top_n_sales(df, n=2):
return df.nlargest(n, 'Sales')

top_sales_by_region = sales_data.groupby('Region').apply(top_n_sales, n=1)
print("\n每个区域销售额最高的记录:")
print(top_sales_by_region)

4.5 时间序列分组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 创建时间序列数据
date_rng = pd.date_range(start='2024-01-01', end='2024-03-31', freq='D')
ts_data = pd.DataFrame({
'Date': date_rng,
'Sales': np.random.randint(100, 500, len(date_rng)),
'Region': np.random.choice(['North', 'South', 'East', 'West'], len(date_rng))
})

# 按时间频率分组
ts_data['Month'] = ts_data['Date'].dt.to_period('M')
monthly_sales = ts_data.groupby('Month')['Sales'].sum()
print("月度销售总额:")
print(monthly_sales)

# 重采样时间序列
ts_data_indexed = ts_data.set_index('Date')
monthly_resampled = ts_data_indexed['Sales'].resample('M').sum()
print("\n重采样后的月度销售:")
print(monthly_resampled)

五、数据透视表高级应用

5.1 基础数据透视表

数据透视表是数据分析中强大的多维汇总工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 创建示例数据
pivot_data = pd.DataFrame({
'Date': ['2024-01-01', '2024-01-01', '2024-01-02', '2024-01-02'] * 2,
'Region': ['North', 'South', 'North', 'South'] * 2,
'Product': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B'],
'Sales': [100, 120, 90, 110, 150, 130, 140, 160],
'Profit': [20, 25, 18, 22, 30, 28, 35, 32]
})

# 基础数据透视表
basic_pivot = pd.pivot_table(pivot_data, values='Sales', index='Region', columns='Product', aggfunc='sum')
print("基础数据透视表:")
print(basic_pivot)

5.2 多维度多指标透视表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 多值多函数透视表
advanced_pivot = pd.pivot_table(pivot_data,
values=['Sales', 'Profit'],
index='Region',
columns='Product',
aggfunc={'Sales': ['sum', 'mean'],
'Profit': ['sum', 'mean', 'std']})
print("高级数据透视表:")
print(advanced_pivot)

# 多索引透视表
multi_index_pivot = pd.pivot_table(pivot_data,
values='Sales',
index=['Date', 'Region'],
columns='Product',
aggfunc='sum')
print("\n多索引数据透视表:")
print(multi_index_pivot)

5.3 透视表高级功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 添加小计和总计
pivot_with_margins = pd.pivot_table(pivot_data,
values='Sales',
index='Region',
columns='Product',
aggfunc='sum',
margins=True,
margins_name='总计')
print("带总计的透视表:")
print(pivot_with_margins)

# 处理缺失值
pivot_data_with_na = pivot_data.copy()
pivot_data_with_na.loc[0, 'Sales'] = np.nan

pivot_filled = pd.pivot_table(pivot_data_with_na,
values='Sales',
index='Region',
columns='Product',
aggfunc='sum',
fill_value=0)
print("\n填充缺失值的透视表:")
print(pivot_filled)

5.4 自定义聚合函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 自定义聚合函数
def profit_margin(profit, sales):
return profit.sum() / sales.sum()

def sales_range(x):
return x.max() - x.min()

# 应用自定义函数
custom_pivot = pd.pivot_table(pivot_data,
values=['Sales', 'Profit'],
index='Region',
columns='Product',
aggfunc={'Sales': ['sum', sales_range],
'Profit': ['sum', 'mean']})

print("自定义聚合函数的透视表:")
print(custom_pivot)

六、综合实战案例

6.1 销售数据分析完整流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 1. 数据准备与加载
def load_and_preprocess_data():
"""加载并预处理销售数据"""
# 创建示例销售数据集
np.random.seed(42)
dates = pd.date_range('2024-01-01', '2024-06-30')
regions = ['North', 'South', 'East', 'West']
products = ['A', 'B', 'C']

data = []
for date in dates:
for region in regions:
for product in products:
sales = np.random.randint(50, 200)
profit = sales * np.random.uniform(0.1, 0.3)
data.append({
'Date': date,
'Region': region,
'Product': product,
'Sales': sales,
'Profit': profit
})

df = pd.DataFrame(data)

# 故意添加一些缺失值和异常值
df.iloc[10:15, 3] = np.nan # 添加缺失值
df.iloc[100:105, 3] = df.iloc[100:105, 3] * 5 # 添加异常值

return df

# 加载数据
sales_df = load_and_preprocess_data()
print("原始数据形状:", sales_df.shape)
print("\n前5行数据:")
print(sales_df.head())

6.2 完整数据处理流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
def comprehensive_data_analysis(df):
"""综合数据分析流程"""

# 1. 数据质量检查
print("=== 数据质量检查 ===")
print("缺失值统计:")
print(df.isnull().sum())

print("\n数据类型:")
print(df.dtypes)

# 2. 数据清洗
print("\n=== 数据清洗 ===")
# 处理缺失值
df_cleaned = df.copy()
df_cleaned['Sales'] = df_cleaned['Sales'].fillna(df_cleaned['Sales'].median())

# 检测并处理异常值
Q1 = df_cleaned['Sales'].quantile(0.25)
Q3 = df_cleaned['Sales'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 缩尾处理异常值
df_cleaned['Sales'] = df_cleaned['Sales'].clip(lower=lower_bound, upper=upper_bound)

print("数据清洗完成")

# 3. 数据分析
print("\n=== 数据分析 ===")

# 基本统计描述
print("销售数据描述性统计:")
print(df_cleaned[['Sales', 'Profit']].describe())

# 分组分析
regional_analysis = df_cleaned.groupby('Region').agg({
'Sales': ['sum', 'mean', 'std'],
'Profit': ['sum', 'mean']
}).round(2)

print("\n区域分析:")
print(regional_analysis)

# 时间序列分析
df_cleaned['Month'] = df_cleaned['Date'].dt.to_period('M')
monthly_trend = df_cleaned.groupby('Month')['Sales'].sum()

print("\n月度销售趋势:")
print(monthly_trend)

# 4. 数据透视表分析
print("\n=== 数据透视表分析 ===")

pivot_analysis = pd.pivot_table(df_cleaned,
values=['Sales', 'Profit'],
index=['Region', 'Product'],
columns='Month',
aggfunc='sum',
margins=True)

print("多维度透视分析:")
print(pivot_analysis)

return df_cleaned

# 执行综合分析
processed_data = comprehensive_data_analysis(sales_df)

6.3 结果可视化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import matplotlib.pyplot as plt
import seaborn as sns

def visualize_analysis_results(df):
"""可视化分析结果"""

plt.figure(figsize=(15, 10))

# 1. 销售分布
plt.subplot(2, 3, 1)
df['Sales'].plot(kind='hist', bins=30, title='销售分布直方图')
plt.xlabel('销售额')

# 2. 区域销售对比
plt.subplot(2, 3, 2)
regional_sales = df.groupby('Region')['Sales'].sum()
regional_sales.plot(kind='bar', title='各区域总销售额')
plt.xticks(rotation=45)

# 3. 产品销售趋势
plt.subplot(2, 3, 3)
product_trend = df.groupby(['Month', 'Product'])['Sales'].sum().unstack()
product_trend.plot(title='产品销售趋势', ax=plt.gca())
plt.xticks(rotation=45)

# 4. 利润vs销售散点图
plt.subplot(2, 3, 4)
plt.scatter(df['Sales'], df['Profit'], alpha=0.5)
plt.xlabel('销售额')
plt.ylabel('利润')
plt.title('销售额vs利润')

# 5. 区域-产品热力图
plt.subplot(2, 3, 5)
heatmap_data = pd.pivot_table(df, values='Sales', index='Region', columns='Product', aggfunc='sum')
sns.heatmap(heatmap_data, annot=True, fmt='.0f', cmap='YlOrRd')
plt.title('区域-产品销售热力图')

# 6. 月度销售趋势
plt.subplot(2, 3, 6)
monthly_sales = df.groupby('Month')['Sales'].sum()
monthly_sales.plot(kind='line', title='月度销售趋势')
plt.xticks(rotation=45)

plt.tight_layout()
plt.show()

# 执行可视化
visualize_analysis_results(processed_data)

七、性能优化与最佳实践

7.1 内存优化技巧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 1. 使用合适的数据类型
def optimize_memory_usage(df):
"""优化DataFrame内存使用"""

original_memory = df.memory_usage(deep=True).sum()
print(f"原始数据内存使用: {original_memory / 1024 ** 2:.2f} MB")

# 数值列类型优化
numeric_columns = df.select_dtypes(include=[np.number]).columns
for col in numeric_columns:
col_min = df[col].min()
col_max = df[col].max()

# 选择最合适的整数类型
if col_min > 0:
if col_max < 255:
df[col] = df[col].astype(np.uint8)
elif col_max < 65535:
df[col] = df[col].astype(np.uint16)
elif col_max < 4294967295:
df[col] = df[col].astype(np.uint32)
else:
if col_min > -128 and col_max < 127:
df[col] = df[col].astype(np.int8)
elif col_min > -32768 and col_max < 32767:
df[col] = df[col].astype(np.int16)
elif col_min > -2147483648 and col_max < 2147483647:
df[col] = df[col].astype(np.int32)

# 分类数据优化
object_columns = df.select_dtypes(include=['object']).columns
for col in object_columns:
if df[col].nunique() / len(df[col]) < 0.5: # 基数较低时使用category
df[col] = df[col].astype('category')

optimized_memory = df.memory_usage(deep=True).sum()
print(f"优化后内存使用: {optimized_memory / 1024 ** 2:.2f} MB")
print(f"内存减少: {(original_memory - optimized_memory) / original_memory * 100:.1f}%")

return df

# 应用内存优化
optimized_df = optimize_memory_usage(processed_data)

7.2 大数据处理策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 分块处理大数据集
def process_large_dataset(file_path, chunk_size=10000):
"""分块处理大型数据集"""

results = []

# 分块读取和处理
for chunk in pd.read_csv(file_path, chunksize=chunk_size):
# 对每个数据块进行处理
processed_chunk = chunk.groupby('category_column').agg({
'numeric_column': 'sum'
})
results.append(processed_chunk)

# 合并结果
final_result = pd.concat(results).groupby(level=0).sum()
return final_result

# 使用Dask进行并行处理(大数据集)
try:
import dask.dataframe as dd
def parallel_processing_with_dask(file_path):
"""使用Dask进行并行处理"""
dask_df = dd.read_csv(file_path)
result = dask_df.groupby('category_column').numeric_column.sum().compute()
return result
except ImportError:
print("Dask未安装,跳过并行处理示例")

通过本教程的系统学习,您已经掌握了Pandas数据处理的全面技能,包括数据类型转换、缺失值处理、异常值检测、分组聚合和数据透视表等高级功能。这些技能将帮助您在实际数据分析工作中更加高效地处理和分析数据。