今日练习主题:数据分析与可视化
今天我们将学习使用Python进行数据分析和可视化,主要使用pandas、numpy、matplotlib和seaborn等库。
练习1:NumPy基础操作
import numpy as np
import matplotlib.pyplot as plt
def numpy_basics():
"""NumPy基础操作"""
print("=== NumPy基础操作 ===")
# 创建数组
arr1 = np.array([1, 2, 3, 4, 5])
arr2 = np.arange(0, 10, 2) # 0到10,步长为2
arr3 = np.linspace(0, 1, 5) # 0到1,5个等间距点
zeros = np.zeros((3, 3)) # 3x3零矩阵
ones = np.ones((2, 4)) # 2x4一矩阵
identity = np.eye(3) # 3x3单位矩阵
random_arr = np.random.rand(5) # 5个随机数
print(f"一维数组: {arr1}")
print(f"等差数组: {arr2}")
print(f"等间距数组: {arr3}")
print(f"零矩阵:
{zeros}")
print(f"一矩阵:
{ones}")
print(f"单位矩阵:
{identity}")
print(f"随机数组: {random_arr}")
# 数组操作
print(f"
数组形状: {arr1.shape}")
print(f"数组维度: {arr1.ndim}")
print(f"数组大小: {arr1.size}")
print(f"数组数据类型: {arr1.dtype}")
# 数学运算
print(f"
数组加法: {arr1 + 10}")
print(f"数组乘法: {arr1 * 2}")
print(f"数组平方: {arr1 ** 2}")
print(f"数组正弦: {np.sin(arr1)}")
# 统计操作
print(f"
数组求和: {np.sum(arr1)}")
print(f"数组均值: {np.mean(arr1)}")
print(f"数组标准差: {np.std(arr1)}")
print(f"数组最大值: {np.max(arr1)}")
print(f"数组最小值: {np.min(arr1)}")
# 二维数组操作
matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(f"
二维数组:
{matrix}")
print(f"转置矩阵:
{matrix.T}")
print(f"矩阵行列式: {np.linalg.det(matrix):.2f}")
print(f"矩阵逆:
{np.linalg.inv(matrix):.2f}")
numpy_basics()
练习2:Pandas数据处理
import pandas as pd
import numpy as np
from datetime import datetime
def pandas_basics():
"""Pandas数据处理基础"""
print("
=== Pandas数据处理 ===")
# 创建Series
series_data = pd.Series([1, 3, 5, np.nan, 6, 8])
print("Series:")
print(series_data)
# 创建DataFrame
dates = pd.date_range('20230101', periods=6)
df = pd.DataFrame({
'日期': dates,
'A': [1, 2, 3, 4, 5, 6],
'B': [10, 20, 30, 40, 50, 60],
'C': [100, 200, 300, 400, 500, 600],
'D': ['北京', '上海', '广州', '深圳', '杭州', '成都']
})
print("
DataFrame:")
print(df)
# 基本信息
print(f"
DataFrame形状: {df.shape}")
print(f"列名: {df.columns.tolist()}")
print(f"索引: {df.index.tolist()}")
print(f"数据类型:
{df.dtypes}")
# 数据选择
print("
选择列A:")
print(df['A'])
print("
选择前3行:")
print(df.head(3))
print("
选择特定行和列:")
print(df.loc[0:2, ['A', 'D']])
# 数据筛选
print("
筛选A列大于3的行:")
print(df[df['A'] > 3])
print("
多条件筛选:")
print(df[(df['A'] > 2) & (df['B'] < 50)])
# 数据排序
print("
按A列降序排序:")
print(df.sort_values('A', ascending=False))
# 数据统计
print("
描述性统计:")
print(df.describe())
# 处理缺失值
df_with_nan = df.copy()
df_with_nan.loc[2, 'A'] = np.nan
df_with_nan.loc[4, 'B'] = np.nan
print("
包含缺失值的数据:")
print(df_with_nan)
print("
填充缺失值:")
print(df_with_nan.fillna(0))
print("
删除包含缺失值的行:")
print(df_with_nan.dropna())
def pandas_advanced():
"""Pandas高级操作"""
print("
=== Pandas高级操作 ===")
# 创建示例数据
sales_data = {
'日期': pd.date_range('2023-01-01', periods=100, freq='D'),
'产品': np.random.choice(['产品A', '产品B', '产品C'], 100),
'销售额': np.random.randint(100, 1000, 100),
'数量': np.random.randint(1, 20, 100),
'地区': np.random.choice(['华北', '华东', '华南', '西部'], 100)
}
df = pd.DataFrame(sales_data)
df['单价'] = df['销售额'] / df['数量']
print("销售数据:")
print(df.head())
# 分组聚合
print("
按产品分组统计:")
product_stats = df.groupby('产品').agg({
'销售额': ['sum', 'mean', 'count'],
'数量': 'sum',
'单价': 'mean'
})
print(product_stats)
# 数据透视表
print("
数据透视表(地区×产品):")
pivot_table = pd.pivot_table(df,
values='销售额',
index='地区',
columns='产品',
aggfunc='sum',
fill_value=0)
print(pivot_table)
# 时间序列分析
df.set_index('日期', inplace=True)
print("
月度销售额统计:")
monthly_sales = df['销售额'].resample('M').sum()
print(monthly_sales)
# 移动平均
df['销售额_7天移动平均'] = df['销售额'].rolling(window=7).mean()
print("
7天移动平均:")
print(df[['销售额', '销售额_7天移动平均']].head(10))
pandas_basics()
pandas_advanced()
练习3:Matplotlib基础可视化
import matplotlib.pyplot as plt
import numpy as np
def matplotlib_basics():
"""Matplotlib基础可视化"""
print("=== Matplotlib基础可视化 ===")
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
# 创建数据
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.tan(x) / 10 # 缩小tan函数的值
# 1. 折线图
plt.figure(figsize=(12, 8))
plt.subplot(2, 2, 1)
plt.plot(x, y1, 'b-', label='sin(x)', linewidth=2)
plt.plot(x, y2, 'r--', label='cos(x)', linewidth=2)
plt.title('三角函数曲线')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.grid(True, alpha=0.3)
# 2. 散点图
plt.subplot(2, 2, 2)
x_scatter = np.random.rand(50) * 10
y_scatter = np.random.rand(50) * 10
sizes = np.random.rand(50) * 100
colors = np.random.rand(50)
plt.scatter(x_scatter, y_scatter, s=sizes, c=colors, alpha=0.6, cmap='viridis')
plt.colorbar(label='颜色值')
plt.title('散点图')
plt.xlabel('X轴')
plt.ylabel('Y轴')
# 3. 柱状图
plt.subplot(2, 2, 3)
categories = ['产品A', '产品B', '产品C', '产品D', '产品E']
values = [23, 45, 56, 12, 67]
bars = plt.bar(categories, values, color=['#FF9999', '#66B2FF', '#99FF99', '#FFD700', '#FF69B4'])
plt.title('产品销售额')
plt.xlabel('产品类别')
plt.ylabel('销售额(万元)')
# 在柱子上添加数值标签
for bar in bars:
height = bar.get_height()
plt.text(bar.get_x() + bar.get_width()/2., height,
f'{height}', ha='center', va='bottom')
# 4. 饼图
plt.subplot(2, 2, 4)
labels = ['技术', '市场', '销售', '行政', '研发']
sizes = [15, 30, 25, 10, 20]
colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99', '#ff99cc']
explode = (0.1, 0, 0, 0, 0) # 突出显示第一部分
plt.pie(sizes, explode=explode, labels=labels, colors=colors,
autopct='%1.1f%%', shadow=True, startangle=90)
plt.title('部门人员分布')
plt.tight_layout()
plt.show()
def matplotlib_advanced():
"""Matplotlib高级可视化"""
print("
=== Matplotlib高级可视化 ===")
# 创建数据
np.random.seed(42) # 设置随机种子保证结果可重复
x = np.linspace(0, 10, 100)
y1 = 2 * x + 1 + np.random.normal(0, 1, 100)
y2 = 0.5 * x**2 - 2 * x + 3 + np.random.normal(0, 3, 100)
# 创建子图网格
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(15, 10))
# 1. 带误差线的折线图
x_error = np.arange(10)
y_error = x_error ** 2
y_err = np.random.rand(10) * 5
ax1.errorbar(x_error, y_error, yerr=y_err, fmt='-o', capsize=5,
capthick=2, elinewidth=2, markersize=8)
ax1.set_title('带误差线的折线图')
ax1.set_xlabel('X轴')
ax1.set_ylabel('Y轴')
ax1.grid(True, alpha=0.3)
# 2. 直方图
data_hist = np.random.normal(170, 10, 1000) # 身高数据
ax2.hist(data_hist, bins=30, density=True, alpha=0.7, color='skyblue',
edgecolor='black')
ax2.set_title('身高分布直方图')
ax2.set_xlabel('身高(cm)')
ax2.set_ylabel('频率')
# 添加正态分布曲线
from scipy.stats import norm
x_hist = np.linspace(data_hist.min(), data_hist.max(), 100)
ax2.plot(x_hist, norm.pdf(x_hist, data_hist.mean(), data_hist.std()),
'r-', linewidth=2)
# 3. 箱线图
data_box = [np.random.normal(0, std, 100) for std in range(1, 4)]
ax3.boxplot(data_box, labels=['组1', '组2', '组3'])
ax3.set_title('箱线图')
ax3.set_ylabel('数值')
# 4. 面积图
x_area = np.linspace(0, 10, 100)
y1_area = np.sin(x_area)
y2_area = np.cos(x_area)
ax4.fill_between(x_area, y1_area, alpha=0.3, label='sin(x)')
ax4.fill_between(x_area, y2_area, alpha=0.3, label='cos(x)')
ax4.plot(x_area, y1_area, 'b-', alpha=0.8)
ax4.plot(x_area, y2_area, 'r-', alpha=0.8)
ax4.set_title('面积图')
ax4.set_xlabel('X轴')
ax4.set_ylabel('Y轴')
ax4.legend()
ax4.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
matplotlib_basics()
matplotlib_advanced()
练习4:Seaborn统计可视化
import seaborn as sns
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
def seaborn_visualization():
"""Seaborn统计可视化"""
print("=== Seaborn统计可视化 ===")
# 设置样式
sns.set_style("whitegrid")
sns.set_palette("husl")
# 创建示例数据
np.random.seed(42)
n = 200
data = pd.DataFrame({
'年龄': np.random.randint(18, 65, n),
'收入': np.random.normal(50000, 15000, n),
'教育年限': np.random.randint(8, 20, n),
'性别': np.random.choice(['男', '女'], n),
'城市': np.random.choice(['北京', '上海', '广州', '深圳'], n),
'满意度': np.random.randint(1, 11, n)
})
# 确保收入为正数
data['收入'] = data['收入'].clip(lower=20000)
print("示例数据:")
print(data.head())
# 创建多图布局
plt.figure(figsize=(15, 12))
# 1. 分布图
plt.subplot(2, 3, 1)
sns.histplot(data=data, x='收入', kde=True, bins=20)
plt.title('收入分布')
# 2. 箱线图
plt.subplot(2, 3, 2)
sns.boxplot(data=data, x='城市', y='收入')
plt.title('各城市收入分布')
plt.xticks(rotation=45)
# 3. 小提琴图
plt.subplot(2, 3, 3)
sns.violinplot(data=data, x='性别', y='收入', hue='性别', split=True)
plt.title('性别收入分布')
# 4. 散点图与回归线
plt.subplot(2, 3, 4)
sns.regplot(data=data, x='年龄', y='收入', scatter_kws={'alpha':0.5})
plt.title('年龄与收入关系')
# 5. 热力图(相关性矩阵)
plt.subplot(2, 3, 5)
numeric_data = data.select_dtypes(include=[np.number])
correlation = numeric_data.corr()
sns.heatmap(correlation, annot=True, cmap='coolwarm', center=0)
plt.title('变量相关性热力图')
# 6. 配对图(小样本)
# 由于配对图较复杂,我们使用子样本
plt.subplot(2, 3, 6)
sample_data = data.sample(50)
sns.scatterplot(data=sample_data, x='年龄', y='收入', hue='城市', size='满意度', sizes=(20, 200))
plt.title('多变量散点图')
plt.tight_layout()
plt.show()
# 7. 分类图
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
sns.barplot(data=data, x='城市', y='收入', hue='性别', ci='sd')
plt.title('各城市性别收入对比')
plt.xticks(rotation=45)
plt.subplot(1, 2, 2)
sns.countplot(data=data, x='城市', hue='性别')
plt.title('各城市性别分布')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
seaborn_visualization()
练习5:实际数据分析案例
def sales_analysis():
"""销售数据分析案例"""
print("=== 销售数据分析案例 ===")
# 创建模拟销售数据
np.random.seed(123)
n_customers = 1000
# 生成客户数据
customers = pd.DataFrame({
'客户ID': range(1, n_customers + 1),
'年龄': np.random.randint(18, 70, n_customers),
'性别': np.random.choice(['男', '女'], n_customers, p=[0.55, 0.45]),
'城市': np.random.choice(['北京', '上海', '广州', '深圳', '杭州', '成都'], n_customers),
'会员等级': np.random.choice(['普通', '银卡', '金卡', '白金'], n_customers, p=[0.6, 0.25, 0.1, 0.05]),
'注册日期': pd.date_range('2020-01-01', periods=n_customers, freq='D')
})
# 生成交易数据
n_transactions = 5000
transactions = pd.DataFrame({
'交易ID': range(1, n_transactions + 1),
'客户ID': np.random.randint(1, n_customers + 1, n_transactions),
'交易日期': pd.date_range('2023-01-01', periods=n_transactions, freq='H'),
'产品类别': np.random.choice(['电子产品', '服装', '家居', '食品', '图书'], n_transactions),
'金额': np.random.exponential(100, n_transactions),
'数量': np.random.randint(1, 5, n_transactions)
})
# 合并数据
merged_data = transactions.merge(customers, on='客户ID')
print("数据概览:")
print(f"客户数量: {len(customers)}")
print(f"交易数量: {len(transactions)}")
print(f"合并后数据形状: {merged_data.shape}")
# 数据分析
print("
=== 数据分析 ===")
# 1. 基本统计
print("交易金额统计:")
print(merged_data['金额'].describe())
# 2. 月度销售趋势
merged_data['月份'] = merged_data['交易日期'].dt.to_period('M')
monthly_sales = merged_data.groupby('月份').agg({
'金额': 'sum',
'交易ID': 'count'
}).rename(columns={'交易ID': '交易次数'})
print("
月度销售趋势:")
print(monthly_sales.tail())
# 3. 产品类别分析
category_analysis = merged_data.groupby('产品类别').agg({
'金额': ['sum', 'mean', 'count'],
'数量': 'sum'
}).round(2)
print("
产品类别分析:")
print(category_analysis)
# 4. 客户分析
customer_analysis = merged_data.groupby('客户ID').agg({
'金额': 'sum',
'交易ID': 'count',
'年龄': 'first',
'性别': 'first',
'城市': 'first',
'会员等级': 'first'
}).rename(columns={'交易ID': '购买次数', '金额': '总消费金额'})
print("
客户分析(前10名):")
print(customer_analysis.nlargest(10, '总消费金额'))
# 可视化分析
plt.figure(figsize=(15, 10))
# 1. 月度销售趋势图
plt.subplot(2, 2, 1)
monthly_sales['金额'].plot(kind='line', marker='o')
plt.title('月度销售额趋势')
plt.xlabel('月份')
plt.ylabel('销售额')
plt.xticks(rotation=45)
plt.grid(True, alpha=0.3)
# 2. 产品类别销售额
plt.subplot(2, 2, 2)
category_sales = merged_data.groupby('产品类别')['金额'].sum().sort_values(ascending=False)
category_sales.plot(kind='bar')
plt.title('各产品类别销售额')
plt.xlabel('产品类别')
plt.ylabel('销售额')
plt.xticks(rotation=45)
# 3. 客户性别分布
plt.subplot(2, 2, 3)
gender_dist = merged_data['性别'].value_counts()
plt.pie(gender_dist.values, labels=gender_dist.index, autopct='%1.1f%%')
plt.title('客户性别分布')
# 4. 会员等级消费分析
plt.subplot(2, 2, 4)
member_sales = merged_data.groupby('会员等级')['金额'].mean().sort_values(ascending=False)
member_sales.plot(kind='bar', color=['gold', 'silver', '#cd7f32', 'lightblue'])
plt.title('各会员等级平均消费金额')
plt.xlabel('会员等级')
plt.ylabel('平均消费金额')
plt.tight_layout()
plt.show()
# 高级分析:RFM分析
print("
=== RFM客户分析 ===")
# 计算RFM值
analysis_date = merged_data['交易日期'].max()
rfm = merged_data.groupby('客户ID').agg({
'交易日期': lambda x: (analysis_date - x.max()).days, # 最近一次购买
'交易ID': 'count', # 购买频率
'金额': 'sum' # 购买金额
}).rename(columns={
'交易日期': 'Recency',
'交易ID': 'Frequency',
'金额': 'Monetary'
})
# RFM分箱
rfm['R_Score'] = pd.qcut(rfm['Recency'], 4, labels=[4, 3, 2, 1]) # 最近购买得分(越小越好)
rfm['F_Score'] = pd.qcut(rfm['Frequency'], 4, labels=[1, 2, 3, 4]) # 购买频率得分
rfm['M_Score'] = pd.qcut(rfm['Monetary'], 4, labels=[1, 2, 3, 4]) # 购买金额得分
rfm['RFM_Score'] = rfm['R_Score'].astype(str) + rfm['F_Score'].astype(str) + rfm['M_Score'].astype(str)
# 客户分层
def rfm_segment(row):
if row['R_Score'] >= 3 and row['F_Score'] >= 3 and row['M_Score'] >= 3:
return '高价值客户'
elif row['R_Score'] >= 2 and row['F_Score'] >= 2:
return '潜力客户'
elif row['R_Score'] >= 3:
return '新客户'
elif row['F_Score'] >= 3:
return '忠实客户'
else:
return '一般客户'
rfm['Segment'] = rfm.apply(rfm_segment, axis=1)
print("RFM客户分层统计:")
print(rfm['Segment'].value_counts())
# RFM可视化
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
segment_counts = rfm['Segment'].value_counts()
plt.pie(segment_counts.values, labels=segment_counts.index, autopct='%1.1f%%')
plt.title('客户分层分布')
plt.subplot(1, 2, 2)
segment_metrics = rfm.groupby('Segment')[['Recency', 'Frequency', 'Monetary']].mean()
segment_metrics.plot(kind='bar', figsize=(10, 6))
plt.title('各客户分层平均指标')
plt.xlabel('客户分层')
plt.ylabel('平均值')
plt.xticks(rotation=45)
plt.legend(['最近购买(天)', '购买频率', '购买金额'])
plt.tight_layout()
plt.show()
sales_analysis()
练习6:时间序列分析
def time_series_analysis():
"""时间序列分析"""
print("=== 时间序列分析 ===")
# 创建时间序列数据
dates = pd.date_range('2020-01-01', '2023-12-31', freq='D')
n = len(dates)
# 生成有趋势、季节性和噪声的时间序列
trend = np.linspace(100, 200, n) # 线性趋势
seasonal = 10 * np.sin(2 * np.pi * np.arange(n) / 365) # 年季节性
noise = np.random.normal(0, 5, n) # 随机噪声
# 合成时间序列
ts_data = trend + seasonal + noise
# 创建DataFrame
ts_df = pd.DataFrame({
'日期': dates,
'销售额': ts_data
})
ts_df.set_index('日期', inplace=True)
print("时间序列数据:")
print(ts_df.head())
# 时间序列可视化
plt.figure(figsize=(15, 10))
# 1. 原始时间序列
plt.subplot(3, 2, 1)
plt.plot(ts_df.index, ts_df['销售额'])
plt.title('原始时间序列')
plt.xlabel('日期')
plt.ylabel('销售额')
plt.grid(True, alpha=0.3)
# 2. 年度对比
plt.subplot(3, 2, 2)
for year in [2020, 2021, 2022, 2023]:
year_data = ts_df[ts_df.index.year == year]
plt.plot(year_data.index.dayofyear, year_data['销售额'], label=str(year))
plt.title('年度对比')
plt.xlabel('一年中的第几天')
plt.ylabel('销售额')
plt.legend()
plt.grid(True, alpha=0.3)
# 3. 移动平均
plt.subplot(3, 2, 3)
ts_df['MA_7'] = ts_df['销售额'].rolling(window=7).mean()
ts_df['MA_30'] = ts_df['销售额'].rolling(window=30).mean()
plt.plot(ts_df.index, ts_df['销售额'], alpha=0.3, label='原始数据')
plt.plot(ts_df.index, ts_df['MA_7'], label='7天移动平均')
plt.plot(ts_df.index, ts_df['MA_30'], label='30天移动平均')
plt.title('移动平均平滑')
plt.xlabel('日期')
plt.ylabel('销售额')
plt.legend()
plt.grid(True, alpha=0.3)
# 4. 季节性分解(简化版)
from statsmodels.tsa.seasonal import seasonal_decompose
# 使用月度数据进行分析
monthly_data = ts_df['销售额'].resample('M').mean()
# 季节性分解
decomposition = seasonal_decompose(monthly_data, model='additive', period=12)
plt.subplot(3, 2, 4)
decomposition.trend.plot()
plt.title('趋势成分')
plt.xlabel('日期')
plt.ylabel('趋势')
plt.grid(True, alpha=0.3)
plt.subplot(3, 2, 5)
decomposition.seasonal.plot()
plt.title('季节性成分')
plt.xlabel('日期')
plt.ylabel('季节性')
plt.grid(True, alpha=0.3)
plt.subplot(3, 2, 6)
decomposition.resid.plot()
plt.title('残差成分')
plt.xlabel('日期')
plt.ylabel('残差')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# 时间序列预测(使用简单方法)
print("
=== 时间序列预测 ===")
# 划分训练集和测试集
train_size = int(len(monthly_data) * 0.8)
train, test = monthly_data[:train_size], monthly_data[train_size:]
# 简单预测方法:使用最后一个值作为预测
last_value = train.iloc[-1]
predictions = pd.Series([last_value] * len(test), index=test.index)
# 计算预测误差
mse = ((predictions - test) ** 2).mean()
mae = (predictions - test).abs().mean()
print(f"预测误差:")
print(f"均方误差 (MSE): {mse:.2f}")
print(f"平均绝对误差 (MAE): {mae:.2f}")
# 预测可视化
plt.figure(figsize=(12, 6))
plt.plot(train.index, train, label='训练数据')
plt.plot(test.index, test, label='实际值')
plt.plot(predictions.index, predictions, label='预测值', linestyle='--')
plt.title('时间序列预测')
plt.xlabel('日期')
plt.ylabel('销售额')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
time_series_analysis()
练习7:地理数据可视化
import geopandas as gpd
import contextily as ctx
def geo_visualization():
"""地理数据可视化"""
print("=== 地理数据可视化 ===")
try:
# 创建模拟的地理数据
cities = pd.DataFrame({
'城市': ['北京', '上海', '广州', '深圳', '杭州', '成都', '武汉', '西安'],
'经度': [116.40, 121.47, 113.23, 114.07, 120.15, 104.06, 114.31, 108.94],
'纬度': [39.90, 31.23, 23.16, 22.62, 30.28, 30.67, 30.52, 34.26],
'人口(万)': [2189, 2428, 1530, 1303, 981, 1658, 1121, 1020],
'GDP(亿元)': [36103, 38701, 25019, 27670, 16106, 17717, 15616, 10020]
})
# 创建GeoDataFrame
gdf = gpd.GeoDataFrame(
cities,
geometry=gpd.points_from_xy(cities.经度, cities.纬度),
crs="EPSG:4326" # WGS84坐标系
)
print("地理数据:")
print(gdf.head())
# 地理可视化
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
# 1. 人口分布图
gdf.plot(ax=ax1,
column='人口(万)',
cmap='Reds',
legend=True,
markersize=gdf['人口(万)']/100, # 根据人口调整点大小
alpha=0.7)
ax1.set_title('中国主要城市人口分布')
ax1.set_xlabel('经度')
ax1.set_ylabel('纬度')
# 添加城市标签
for idx, row in gdf.iterrows():
ax1.annotate(row['城市'], (row['经度'], row['纬度']),
xytext=(5, 5), textcoords='offset points', fontsize=8)
# 2. GDP分布图
gdf.plot(ax=ax2,
column='GDP(亿元)',
cmap='Blues',
legend=True,
markersize=gdf['GDP(亿元)']/1000, # 根据GDP调整点大小
alpha=0.7)
ax2.set_title('中国主要城市GDP分布')
ax2.set_xlabel('经度')
ax2.set_ylabel('纬度')
# 添加城市标签
for idx, row in gdf.iterrows():
ax2.annotate(row['城市'], (row['经度'], row['纬度']),
xytext=(5, 5), textcoords='offset points', fontsize=8)
plt.tight_layout()
plt.show()
except ImportError:
print("geopandas或contextily库未安装,跳过地理可视化")
print("请安装: pip install geopandas contextily")
geo_visualization()
今日挑战:
创建一个完整的数据分析报告,包含数据清洗、探索性分析、统计建模和可视化。
# 挑战练习:完整的数据分析报告
def comprehensive_data_analysis():
"""完整的数据分析报告"""
print("=== 完整的数据分析报告 ===")
# 1. 数据准备和清洗
print("1. 数据准备和清洗")
# 创建综合数据集
np.random.seed(42)
n = 1000
data = pd.DataFrame({
'年龄': np.random.normal(35, 10, n).astype(int),
'年收入(万)': np.random.normal(15, 5, n),
'教育年限': np.random.randint(8, 20, n),
'工作经验': np.random.randint(0, 40, n),
'城市等级': np.random.choice([1, 2, 3], n, p=[0.2, 0.5, 0.3]), # 1-一线, 2-二线, 3-三线
'行业': np.random.choice(['科技', '金融', '制造', '教育', '医疗'], n),
'婚姻状况': np.random.choice(['未婚', '已婚', '离异'], n, p=[0.4, 0.5, 0.1]),
'是否有房': np.random.choice([0, 1], n, p=[0.3, 0.7]),
'是否有车': np.random.choice([0, 1], n, p=[0.4, 0.6]),
'信用评分': np.random.randint(300, 850, n)
})
# 数据清洗
# 确保年龄在合理范围内
data['年龄'] = data['年龄'].clip(18, 65)
# 确保收入为正数
data['年收入(万)'] = data['年收入(万)'].clip(3, 50)
# 添加一些缺失值
missing_indices = np.random.choice(n, size=50, replace=False)
data.loc[missing_indices, '年收入(万)'] = np.nan
print("原始数据形状:", data.shape)
print("缺失值统计:")
print(data.isnull().sum())
# 处理缺失值
data_clean = data.copy()
data_clean['年收入(万)'] = data_clean['年收入(万)'].fillna(data_clean['年收入(万)'].median())
print("
清洗后数据形状:", data_clean.shape)
print("清洗后缺失值统计:")
print(data_clean.isnull().sum())
# 2. 探索性数据分析
print("
2. 探索性数据分析")
# 基本统计
print("数值变量描述性统计:")
print(data_clean.describe())
print("
分类变量统计:")
categorical_cols = ['城市等级', '行业', '婚姻状况', '是否有房', '是否有车']
for col in categorical_cols:
print(f"
{col}分布:")
print(data_clean[col].value_counts())
# 3. 相关性分析
print("
3. 相关性分析")
# 计算相关系数矩阵
numeric_cols = ['年龄', '年收入(万)', '教育年限', '工作经验', '信用评分']
correlation_matrix = data_clean[numeric_cols].corr()
plt.figure(figsize=(10, 8))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', center=0, square=True)
plt.title('变量相关性热力图')
plt.tight_layout()
plt.show()
# 4. 多维度可视化分析
print("
4. 多维度可视化分析")
fig = plt.figure(figsize=(18, 12))
# 4.1 收入分布
plt.subplot(2, 3, 1)
plt.hist(data_clean['年收入(万)'], bins=30, alpha=0.7, color='skyblue', edgecolor='black')
plt.title('年收入分布')
plt.xlabel('年收入(万)')
plt.ylabel('频数')
# 4.2 收入与教育程度关系
plt.subplot(2, 3, 2)
sns.boxplot(data=data_clean, x='教育年限', y='年收入(万)')
plt.title('教育程度与收入关系')
plt.xticks(rotation=45)
# 4.3 行业收入对比
plt.subplot(2, 3, 3)
industry_income = data_clean.groupby('行业')['年收入(万)'].mean().sort_values(ascending=False)
industry_income.plot(kind='bar')
plt.title('各行业平均收入')
plt.ylabel('平均年收入(万)')
plt.xticks(rotation=45)
# 4.4 城市等级与收入
plt.subplot(2, 3, 4)
sns.violinplot(data=data_clean, x='城市等级', y='年收入(万)')
plt.title('不同城市等级收入分布')
# 4.5 婚姻状况与收入
plt.subplot(2, 3, 5)
marital_income = data_clean.groupby('婚姻状况')['年收入(万)'].mean()
marital_income.plot(kind='pie', autopct='%1.1f%%')
plt.title('婚姻状况收入分布')
# 4.6 房产与收入关系
plt.subplot(2, 3, 6)
sns.scatterplot(data=data_clean, x='年龄', y='年收入(万)', hue='是否有房', style='是否有车')
plt.title('年龄、收入与资产关系')
plt.tight_layout()
plt.show()
# 5. 统计建模
print("
5. 统计建模")
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.preprocessing import LabelEncoder
# 数据预处理
modeling_data = data_clean.copy()
# 编码分类变量
label_encoders = {}
for col in ['行业', '婚姻状况']:
le = LabelEncoder()
modeling_data[col] = le.fit_transform(modeling_data[col])
label_encoders[col] = le
# 准备特征和目标变量
X = modeling_data.drop('年收入(万)', axis=1)
y = modeling_data['年收入(万)']
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 线性回归模型
model = LinearRegression()
model.fit(X_train, y_train)
# 预测和评估
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
print(f"模型评估结果:")
print(f"均方误差 (MSE): {mse:.2f}")
print(f"决定系数 (R²): {r2:.2f}")
# 特征重大性
feature_importance = pd.DataFrame({
'特征': X.columns,
'系数': model.coef_
}).sort_values('系数', key=abs, ascending=False)
print("
特征重大性:")
print(feature_importance)
# 6. 预测结果可视化
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.scatter(y_test, y_pred, alpha=0.5)
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--')
plt.xlabel('实际值')
plt.ylabel('预测值')
plt.title('预测 vs 实际值')
plt.subplot(1, 2, 2)
residuals = y_test - y_pred
plt.scatter(y_pred, residuals, alpha=0.5)
plt.axhline(y=0, color='r', linestyle='--')
plt.xlabel('预测值')
plt.ylabel('残差')
plt.title('残差分析')
plt.tight_layout()
plt.show()
# 7. 生成分析报告摘要
print("
" + "="*50)
print("数据分析报告摘要")
print("="*50)
print(f"数据集大小: {data_clean.shape}")
print(f"平均年龄: {data_clean['年龄'].mean():.1f}岁")
print(f"平均年收入: {data_clean['年收入(万)'].mean():.1f}万元")
print(f"最高收入行业: {industry_income.index[0]} ({industry_income.iloc[0]:.1f}万元)")
print(f"模型预测准确度 (R²): {r2:.3f}")
# 关键发现
print("
关键发现:")
print("1. 教育程度与收入呈正相关关系")
print("2. 不同行业间存在明显的收入差异")
print("3. 一线城市收入水平显著高于其他城市")
print("4. 模型能够较好地预测收入水平")
# 提议
print("
提议:")
print("1. 重点关注高收入行业的人才培养")
print("2. 加强职业教育和继续教育")
print("3. 优化区域人才发展政策")
print("4. 基于模型结果优化人力资源配置")
# 运行完整的数据分析
comprehensive_data_analysis()
学习提示:
- NumPy:数值计算基础,数组操作和数学函数
- Pandas:数据处理核心,数据清洗、转换和分析
- Matplotlib:基础可视化,创建各种静态图表
- Seaborn:统计可视化,基于Matplotlib的高级接口
- 数据清洗:处理缺失值、异常值、数据类型转换
- 探索性分析:统计描述、相关性分析、分布分析
- 统计建模:回归分析、分类模型、模型评估
- 报告生成:结果解释、可视化展示、业务洞察
明天我们将学习机器学习和人工智能基础!坚持练习,你的数据分析能力会越来越强!
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END

















暂无评论内容