引言:为什么Python数据分析是职场必备技能?
在当今数据驱动的商业环境中,Python已经成为数据分析领域的绝对主流工具。根据最新的行业调查,超过85%的数据分析师使用Python作为主要编程语言。这不仅仅是因为Python语法简洁易学,更重要的是它拥有强大的生态系统,特别是pandas、numpy和matplotlib/seaborn这三大核心库,它们构成了数据分析的”黄金三角”。
对于想要提升职场竞争力的专业人士来说,掌握Python数据分析意味着:
- 效率提升:自动化重复性数据处理工作,将原本需要数小时的工作缩短到几分钟
- 洞察力增强:通过高级分析技术发现数据中隐藏的商业价值
- 决策支持:用数据驱动的洞察为管理层提供可靠的决策依据
- 职业发展:根据LinkedIn数据,具备Python数据分析技能的专业人士平均薪资比同行高出30-50%
本课程将带你从基础入门到精通,系统掌握pandas、numpy和可视化技巧,解决实际工作中的数据清洗与分析难题。
第一部分:NumPy基础与进阶——高效数值计算的基石
NumPy核心概念:ndarray数组
NumPy是Python科学计算的基础库,它提供了高性能的多维数组对象和相关的操作。理解ndarray是掌握NumPy的关键。
import numpy as np
# 创建不同类型的数组
# 1. 从列表创建数组
arr1 = np.array([1, 2, 3, 4, 5])
print(f"一维数组: {arr1}")
print(f"数组类型: {type(arr1)}")
print(f"数组形状: {arr1.shape}")
print(f"数组维度: {arr1.ndim}")
# 2. 创建特殊数组
zeros_arr = np.zeros((3, 4)) # 3行4列的零矩阵
ones_arr = np.ones((2, 3)) # 2行3列的单位矩阵
identity_arr = np.eye(3) # 3x3单位矩阵
range_arr = np.arange(0, 10, 2) # 等差数列: 0,2,4,6,8
linspace_arr = np.linspace(0, 1, 5) # 0到1之间等分5个点
print("\n特殊数组示例:")
print("零矩阵:\n", zeros_arr)
print("单位矩阵:\n", identity_arr)
print("等差数列:", range_arr)
print("等分点:", linspace_arr)
# 3. 随机数组
random_arr = np.random.rand(3, 3) # 0-1均匀分布
normal_arr = np.random.randn(3, 3) # 标准正态分布
int_arr = np.random.randint(0, 10, (3, 3)) # 0-10随机整数
print("\n随机数组:\n", random_arr)
NumPy数组操作与索引
# 数组索引和切片
arr = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]])
# 基本索引
print("第2行:", arr[1]) # 索引从0开始
print("第3列:", arr[:, 2]) # 所有行,第3列
print("第2行第3列:", arr[1, 2])
# 切片操作
print("前两行:\n", arr[:2, :])
print("第2-3列:\n", arr[:, 1:3])
print("逆序:\n", arr[::-1, ::-1])
# 布尔索引
bool_idx = arr > 5
print("大于5的元素:\n", arr[bool_idx])
print("大于5的元素个数:", np.sum(arr > 5))
# 花式索引
indices = [0, 2] # 选择第0行和第2行
print("选择指定行:\n", arr[indices])
# 形状变换
reshaped = arr.reshape(4, 3)
print("重塑形状(4,3):\n", reshaped)
# 数组拼接
arr2 = np.array([[13, 14, 15, 16]])
vertical = np.vstack((arr, arr2)) # 垂直拼接
horizontal = np.hstack((arr, arr.T)) # 水平拼接
print("垂直拼接:\n", vertical)
print("水平拼接:\n", horizontal)
NumPy广播机制与向量化运算
广播是NumPy最强大的特性之一,它允许不同形状的数组进行算术运算。
# 广播机制示例
a = np.array([1, 2, 3, 4])
b = 2 # 标量
# 标量与数组运算(广播)
result = a + b
print(f"a + b = {result}") # [3,4,5,6]
# 数组与数组运算
arr1 = np.array([[1, 2, 3],
[4, 5, 6]])
arr2 = np.array([10, 20, 30]) # 形状(3,),广播到(2,3)
result = arr1 + arr2
print("数组广播加法:\n", result)
# 不同形状的广播
arr3 = np.array([[1], [2], [3]]) # 形状(3,1)
arr4 = np.array([10, 20, 30, 40]) # 形状(4,)
# 广播结果为(3,4)
result = arr3 + arr4
print("复杂广播:\n", result)
# 向量化运算 vs 循环
import time
# 循环方式
def loop_multiply(arr, scalar):
result = np.zeros_like(arr)
for i in range(arr.shape[0]):
for j in range(arr.shape[1]):
result[i, j] = arr[i, j] * scalar
return result
# 向量化方式
def vectorized_multiply(arr, scalar):
return arr * scalar
# 性能对比
large_arr = np.random.rand(1000, 1000)
scalar = 2.5
start = time.time()
loop_result = loop_multiply(large_arr, scalar)
loop_time = time.time() - start
start = time.time()
vectorized_result = vectorized_multiply(large_arr, scalar)
vectorized_time = time.time() - start
print(f"循环方式耗时: {loop_time:.4f}秒")
print(f"向量化方式耗时: {vectorized_time:.4f}秒")
print(f"性能提升: {loop_time/vectorized_time:.1f}倍")
NumPy高级数学运算
# 统计运算
arr = np.random.randn(5, 5) * 10 # 5x5随机数组,放大10倍
print("原始数组:\n", arr)
print(f"平均值: {np.mean(arr):.2f}")
print(f"中位数: {np.median(arr):.2f}")
print(f"标准差: {np.std(arr):.2f}")
print(f"方差: {np.var(arr):.2f}")
print(f"最小值: {np.min(arr):.2f}")
print(f"最大值: {np.max(arr):.2f}")
# 沿轴运算
print("\n沿轴运算:")
print("每行平均值:", np.mean(arr, axis=1))
print("每列平均值:", np.mean(arr, axis=0))
# 线性代数
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# 矩阵乘法
C = np.dot(A, B) # 或者 A @ B
print("\n矩阵乘法:\n", C)
# 矩阵的逆
A_inv = np.linalg.inv(A)
print("矩阵A的逆:\n", A_inv)
# 特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eig(A)
print("特征值:", eigenvalues)
print("特征向量:\n", eigenvectors)
# 求解线性方程组 Ax = b
b = np.array([5, 11])
x = np.linalg.solve(A, b)
print("线性方程组解:", x)
第二部分:Pandas数据处理——从数据清洗到高级分析
DataFrame基础与数据读取
Pandas是基于NumPy构建的数据分析库,提供了DataFrame这一核心数据结构,非常适合处理表格数据。
import pandas as pd
import numpy as np
# 创建DataFrame
# 1. 从字典创建
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [25, 30, 35, 28],
'部门': ['技术部', '市场部', '技术部', '人事部'],
'薪资': [8000, 12000, 15000, 9000],
'入职日期': pd.date_range('2020-01-01', periods=4)
}
df = pd.DataFrame(data)
print("原始DataFrame:")
print(df)
print(f"\nDataFrame形状: {df.shape}")
print(f"数据类型:\n{df.dtypes}")
# 2. 从CSV/Excel读取
# df = pd.read_csv('data.csv', encoding='utf-8')
# df = pd.read_excel('data.xlsx', sheet_name='Sheet1')
# 3. 从SQL数据库读取
# import sqlite3
# conn = sqlite3.connect('database.db')
# df = pd.read_sql('SELECT * FROM table_name', conn)
# 查看数据基本信息
print("\n数据基本信息:")
print(df.info())
print("\n统计描述:")
print(df.describe())
print("\n前3行数据:")
print(df.head(3))
print("\n后2行数据:")
print(df.tail(2))
# 数据选择与索引
print("\n=== 数据选择 ===")
print("选择单列:")
print(df['姓名'])
print("\n选择多列:")
print(df[['姓名', '部门', '薪资']])
print("\n按位置选择:")
print(df.iloc[1:3, 1:3]) # 第1-2行,第1-2列
print("\n按标签选择:")
print(df.loc[1:2, ['姓名', '薪资']]) # 索引1-2,指定列
print("\n条件选择:")
print(df[df['薪资'] > 10000]) # 薪资大于10000的员工
print("\n多条件选择:")
print(df[(df['部门'] == '技术部') & (df['年龄'] < 30)])
数据清洗与预处理
数据清洗是数据分析中最耗时但最重要的步骤,通常占整个分析流程的60-80%时间。
# 创建包含问题的示例数据
data = {
'姓名': ['张三', '李四', '王五', '赵六', '孙七', None, '周八'],
'年龄': [25, 30, 35, 28, 40, 22, None],
'部门': ['技术部', '市场部', '技术部', '人事部', '技术部', '市场部', '技术部'],
'薪资': [8000, 12000, 15000, 9000, 18000, 8500, 20000],
'邮箱': ['zhang3@company.com', 'li4@company.com', 'wang5@company.com',
'zhao6@company.com', 'sun7@company.com', None, 'zhou8@company.com'],
'绩效': ['A', 'B', 'A', 'C', 'A', 'B', 'A']
}
df = pd.DataFrame(data)
print("原始数据(包含问题):")
print(df)
# 1. 处理缺失值
print("\n=== 缺失值处理 ===")
print("缺失值统计:")
print(df.isnull().sum())
# 删除缺失值
df_dropped = df.dropna() # 删除任何包含NaN的行
print("\n删除缺失值后:")
print(df_dropped)
# 填充缺失值
df_filled = df.copy()
df_filled['姓名'] = df_filled['姓名'].fillna('未知')
df_filled['年龄'] = df_filled['年龄'].fillna(df_filled['年龄'].median())
df_filled['邮箱'] = df_filled['邮箱'].fillna('unknown@company.com')
print("\n填充缺失值后:")
print(df_filled)
# 2. 数据类型转换
print("\n=== 数据类型转换 ===")
df_clean = df_filled.copy()
df_clean['年龄'] = df_clean['年龄'].astype(int) # 转换为整数
print("转换后数据类型:")
print(df_clean.dtypes)
# 3. 处理重复值
print("\n=== 重复值处理 ===")
df_dup = pd.DataFrame({
'姓名': ['张三', '李四', '张三', '王五'],
'年龄': [25, 30, 25, 35],
'部门': ['技术部', '市场部', '技术部', '技术部']
})
print("包含重复值的数据:")
print(df_dup)
print("\n重复值数量:", df_dup.duplicated().sum())
print("\n删除重复值:")
print(df_dup.drop_duplicates())
# 4. 数据标准化与规范化
print("\n=== 数据标准化 ===")
# Z-score标准化
df_clean['薪资_zscore'] = (df_clean['薪资'] - df_clean['薪资'].mean()) / df_clean['薪资'].std()
# Min-Max归一化
df_clean['薪资_minmax'] = (df_clean['薪资'] - df_clean['薪资'].min()) / (df_clean['薪资'].max() - df_clean['薪资'].min())
print("标准化后的薪资:")
print(df_clean[['薪资', '薪资_zscore', '薪资_minmax']])
# 5. 异常值检测与处理
print("\n=== 异常值处理 ===")
# 使用IQR方法检测异常值
Q1 = df_clean['薪资'].quantile(0.25)
Q3 = df_clean['薪资'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
print(f"薪资正常范围: [{lower_bound:.2f}, {upper_bound:.2f}]")
outliers = df_clean[(df_clean['薪资'] < lower_bound) | (df_clean['薪资'] > upper_bound)]
print("异常值:")
print(outliers)
# 异常值处理:替换为边界值
df_clean['薪资_处理后'] = df_clean['薪资'].clip(lower=lower_bound, upper=upper_bound)
print("\n处理异常值后:")
print(df_clean[['薪资', '薪资_处理后']])
数据转换与高级操作
# 1. 数据分组与聚合
print("=== 数据分组与聚合 ===")
grouped = df_clean.groupby('部门')
print("按部门分组:")
for name, group in grouped:
print(f"\n部门: {name}")
print(group[['姓名', '薪资']])
# 聚合统计
agg_result = df_clean.groupby('部门').agg({
'薪资': ['mean', 'max', 'min', 'count'],
'年龄': 'mean'
})
print("\n聚合统计:")
print(agg_result)
# 2. 数据透视表
print("\n=== 数据透视表 ===")
pivot_df = pd.DataFrame({
'日期': ['2023-01', '2023-01', '2023-02', '2023-02', '2023-03', '2023-03'],
'产品': ['A', 'B', 'A', 'B', 'A', 'B'],
'销售额': [100, 150, 120, 180, 110, 160],
'利润': [20, 30, 25, 35, 22, 32]
})
pivot = pd.pivot_table(pivot_df,
values=['销售额', '利润'],
index='日期',
columns='产品',
aggfunc='sum')
print("透视表:")
print(pivot)
# 3. apply函数与自定义转换
print("\n=== apply函数 ===")
def categorize_age(age):
if age < 30:
return '青年'
elif age < 40:
return '中年'
else:
return '老年'
df_clean['年龄段'] = df_clean['年龄'].apply(categorize_age)
print("添加年龄段:")
print(df_clean[['姓名', '年龄', '年龄段']])
# 对多列应用函数
def salary_level(row):
if row['薪资'] > 15000:
return '高薪'
elif row['薪资'] > 10000:
return '中薪'
else:
return '低薪'
df_clean['薪资等级'] = df_clean.apply(salary_level, axis=1)
print("\n添加薪资等级:")
print(df_clean[['姓名', '薪资', '薪资等级']])
# 4. 合并与连接
print("\n=== 数据合并 ===")
df1 = pd.DataFrame({
'员工ID': [1, 2, 3, 4],
'姓名': ['张三', '李四', '王五', '赵六']
})
df2 = pd.DataFrame({
'员工ID': [1, 2, 3, 5],
'绩效': ['A', 'B', 'A', 'C']
})
# 合并(类似SQL的JOIN)
merged = pd.merge(df1, df2, on='员工ID', how='inner')
print("内连接:")
print(merged)
merged_left = pd.merge(df1, df2, on='员工ID', how='left')
print("\n左连接:")
print(merged_left)
# 5. 时间序列处理
print("\n=== 时间序列处理 ===")
date_df = pd.DataFrame({
'date': pd.date_range('2023-01-01', periods=10, freq='D'),
'value': np.random.randint(100, 200, 10)
})
date_df['year'] = date_df['date'].dt.year
date_df['month'] = date_df['date'].dt.month
date_df['dayofweek'] = date_df['date'].dt.dayofweek
date_df['is_weekend'] = date_df['dayofweek'].isin([5, 6])
print("时间特征提取:")
print(date_df)
实战案例:销售数据分析
# 生成模拟销售数据
np.random.seed(42)
dates = pd.date_range('2023-01-01', '2023-12-31', freq='D')
products = ['笔记本电脑', '显示器', '键盘', '鼠标', '耳机']
regions = ['华北', '华东', '华南', '西南']
sales_data = []
for date in dates:
for _ in range(5): # 每天5条记录
product = np.random.choice(products)
region = np.random.choice(regions)
quantity = np.random.randint(1, 10)
unit_price = np.random.randint(50, 500)
sales_data.append({
'日期': date,
'产品': product,
'区域': region,
'数量': quantity,
'单价': unit_price,
'销售额': quantity * unit_price
})
sales_df = pd.DataFrame(sales_data)
print("销售数据前5行:")
print(sales_df.head())
# 1. 基础统计分析
print("\n=== 基础统计 ===")
print(f"总销售额: {sales_df['销售额'].sum():,.2f}")
print(f"平均日销售额: {sales_df.groupby('日期')['销售额'].sum().mean():,.2f}")
print("\n按产品统计:")
product_stats = sales_df.groupby('产品').agg({
'销售额': ['sum', 'mean', 'count'],
'数量': 'sum'
}).round(2)
print(product_stats)
# 2. 时间趋势分析
print("\n=== 时间趋势 ===")
monthly_sales = sales_df.groupby(sales_df['日期'].dt.to_period('M'))['销售额'].sum()
print("月度销售额:")
print(monthly_sales)
# 3. 区域分析
print("\n=== 区域分析 ===")
region_analysis = sales_df.groupby(['区域', '产品'])['销售额'].sum().unstack()
print("各区域产品销售额:")
print(region_analysis)
# 4. 畅销产品分析
print("\n=== 畅销产品分析 ===")
top_products = sales_df.groupby('产品')['销售额'].sum().sort_values(ascending=False)
print("产品销售额排名:")
print(top_products)
# 5. 数据透视表分析
print("\n=== 数据透视表分析 ===")
pivot_sales = pd.pivot_table(sales_df,
values='销售额',
index='区域',
columns='产品',
aggfunc='sum',
margins=True,
margins_name='总计')
print("区域-产品销售透视表:")
print(pivot_sales)
第三部分:数据可视化——让数据说话
Matplotlib基础绘图
Matplotlib是Python最基础的绘图库,虽然语法相对繁琐,但功能强大且灵活。
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 设置中文字体(解决中文显示问题)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
# 1. 折线图
plt.figure(figsize=(10, 6))
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
plt.plot(x, y1, label='sin(x)', color='blue', linewidth=2, linestyle='-')
plt.plot(x, y2, label='cos(x)', color='red', linewidth=2, linestyle='--')
plt.title('正弦和余弦函数', fontsize=16)
plt.xlabel('X轴', fontsize=12)
plt.ylabel('Y轴', fontsize=12)
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
# 2. 散点图
plt.figure(figsize=(8, 6))
np.random.seed(42)
x = np.random.normal(0, 1, 100)
y = 2 * x + np.random.normal(0, 0.5, 100)
plt.scatter(x, y, c='purple', alpha=0.6, s=50)
plt.title('散点图示例', fontsize=16)
plt.xlabel('X变量', fontsize=12)
plt.ylabel('Y变量', fontsize=12)
plt.show()
# 3. 柱状图
plt.figure(figsize=(10, 6))
categories = ['产品A', '产品B', '产品C', '产品D', '产品E']
values = [25, 40, 30, 35, 28]
plt.bar(categories, values, color=['#FF9999', '#66B2FF', '#99FF99', '#FFCC99', '#CC99FF'])
plt.title('产品销量对比', fontsize=16)
plt.xlabel('产品', fontsize=12)
plt.ylabel('销量', fontsize=12)
plt.xticks(rotation=45)
plt.show()
# 4. 直方图
plt.figure(figsize=(10, 6))
data = np.random.randn(1000)
plt.hist(data, bins=30, color='skyblue', edgecolor='black', alpha=0.7)
plt.title('正态分布直方图', fontsize=16)
plt.xlabel('数值', fontsize=12)
plt.ylabel('频数', fontsize=12)
plt.show()
# 5. 饼图
plt.figure(figsize=(8, 8))
sizes = [30, 25, 15, 20, 10]
labels = ['产品A', '产品B', '产品C', '产品D', '产品E']
colors = ['#FF9999', '#66B2FF', '#99FF99', '#FFCC99', '#CC99FF']
plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%', startangle=90)
plt.title('市场份额分布', fontsize=16)
plt.show()
# 6. 子图(多图合一)
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 折线图
axes[0, 0].plot(x, y1, color='blue')
axes[0, 0].set_title('折线图')
# 散点图
axes[0, 1].scatter(x, y, color='red', alpha=0.6)
axes[0, 1].set_title('散点图')
# 柱状图
axes[1, 0].bar(categories, values, color='green')
axes[1, 0].set_title('柱状图')
axes[1, 0].tick_params(axis='x', rotation=45)
# 直方图
axes[1, 1].hist(data, bins=20, color='purple', alpha=0.7)
axes[1, 1].set_title('直方图')
plt.tight_layout()
plt.show()
Seaborn高级可视化
Seaborn是基于Matplotlib的高级绘图库,提供了更美观的默认样式和更简单的API。
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# 设置Seaborn样式
sns.set_style("whitegrid")
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建示例数据
np.random.seed(42)
data = pd.DataFrame({
'类别': np.random.choice(['A', 'B', 'C'], 200),
'数值1': np.random.normal(0, 1, 200),
'数值2': np.random.normal(2, 1.5, 200),
'分组': np.random.choice(['X', 'Y'], 200)
})
# 1. 分布图
plt.figure(figsize=(12, 4))
plt.subplot(1, 3, 1)
sns.histplot(data=data, x='数值1', kde=True, color='blue')
plt.title('直方图+密度曲线')
plt.subplot(1, 3, 2)
sns.boxplot(data=data, x='类别', y='数值1', palette='Set2')
plt.title('箱线图')
plt.subplot(1, 3, 3)
sns.violinplot(data=data, x='类别', y='数值1', palette='Set3')
plt.title('小提琴图')
plt.tight_layout()
plt.show()
# 2. 关系图
plt.figure(figsize=(12, 4))
plt.subplot(1, 3, 1)
sns.scatterplot(data=data, x='数值1', y='数值2', hue='类别', style='分组', s=60)
plt.title('散点图')
plt.subplot(1, 3, 2)
sns.lineplot(data=data, x='数值1', y='数值2', hue='类别')
plt.title('线图')
plt.subplot(1, 3, 3)
sns.regplot(data=data, x='数值1', y='数值2', scatter_kws={'alpha':0.5})
plt.title('回归图')
plt.tight_layout()
plt.show()
# 3. 分类图
plt.figure(figsize=(12, 4))
plt.subplot(1, 3, 1)
sns.barplot(data=data, x='类别', y='数值1', hue='分组', ci=None)
plt.title('条形图')
plt.subplot(1, 3, 2)
sns.countplot(data=data, x='类别', hue='分组', palette='viridis')
plt.title('计数图')
plt.subplot(1, 3, 3)
sns.pointplot(data=data, x='类别', y='数值1', hue='分组', ci=None)
plt.title('点图')
plt.tight_layout()
plt.show()
# 4. 矩阵图
plt.figure(figsize=(10, 6))
corr_matrix = data[['数值1', '数值2']].corr()
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', center=0)
plt.title('相关性热力图')
plt.show()
# 5. 配对图
sns.pairplot(data, hue='类别', vars=['数值1', '数值2'], palette='husl')
plt.suptitle('配对图', y=1.02)
plt.show()
# 6. 分布矩阵
sns.jointplot(data=data, x='数值1', y='数值2', kind='scatter', height=6)
plt.suptitle('联合分布图', y=1.02)
plt.show()
实战案例:销售数据可视化分析
# 继续使用之前的销售数据
sales_df = pd.DataFrame(sales_data)
# 1. 月度销售趋势
plt.figure(figsize=(12, 6))
monthly_sales = sales_df.groupby(sales_df['日期'].dt.to_period('M'))['销售额'].sum()
monthly_sales.index = monthly_sales.index.astype(str)
plt.plot(monthly_sales.index, monthly_sales.values, marker='o', linewidth=2, markersize=8)
plt.title('2023年月度销售趋势', fontsize=16)
plt.xlabel('月份', fontsize=12)
plt.ylabel('销售额', fontsize=12)
plt.xticks(rotation=45)
plt.grid(True, alpha=0.3)
plt.show()
# 2. 产品销售对比
plt.figure(figsize=(12, 6))
product_sales = sales_df.groupby('产品')['销售额'].sum().sort_values(ascending=False)
sns.barplot(x=product_sales.index, y=product_sales.values, palette='viridis')
plt.title('各产品销售额对比', fontsize=16)
plt.xlabel('产品', fontsize=12)
plt.ylabel('销售额', fontsize=12)
plt.xticks(rotation=45)
plt.show()
# 3. 区域销售分布
plt.figure(figsize=(10, 8))
region_sales = sales_df.groupby('区域')['销售额'].sum()
plt.pie(region_sales.values, labels=region_sales.index, autopct='%1.1f%%',
colors=sns.color_palette('pastel'))
plt.title('各区域销售额占比', fontsize=16)
plt.show()
# 4. 产品-区域热力图
plt.figure(figsize=(10, 6))
pivot_data = sales_df.groupby(['产品', '区域'])['销售额'].sum().unstack()
sns.heatmap(pivot_data, annot=True, fmt='.0f', cmap='YlOrRd', linewidths=0.5)
plt.title('产品-区域销售额热力图', fontsize=16)
plt.xlabel('区域', fontsize=12)
plt.ylabel('产品', fontsize=12)
plt.show()
# 5. 销售分布直方图
plt.figure(figsize=(10, 6))
sns.histplot(data=sales_df, x='销售额', bins=50, kde=True, color='steelblue')
plt.title('销售额分布', fontsize=16)
plt.xlabel('单笔销售额', fontsize=12)
plt.ylabel('频数', fontsize=12)
plt.show()
# 6. 散点矩阵(多变量关系)
plt.figure(figsize=(10, 8))
sns.pairplot(sales_df[['数量', '单价', '销售额', '产品']],
hue='产品',
palette='husl',
diag_kind='kde')
plt.suptitle('销售数据多变量关系', y=1.02)
plt.show()
第四部分:综合实战——解决真实数据分析难题
案例:电商用户行为分析
# 生成模拟电商用户行为数据
np.random.seed(42)
n_users = 1000
n_products = 50
# 用户基础信息
user_data = {
'user_id': range(1, n_users + 1),
'age': np.random.randint(18, 65, n_users),
'gender': np.random.choice(['男', '女'], n_users, p=[0.48, 0.52]),
'city': np.random.choice(['北京', '上海', '广州', '深圳', '杭州'], n_users),
'register_date': pd.date_range('2022-01-01', periods=n_users, freq='D')
}
# 商品信息
product_data = {
'product_id': range(1, n_products + 1),
'category': np.random.choice(['电子产品', '服装', '食品', '家居', '美妆'], n_products),
'price': np.random.randint(50, 1000, n_products)
}
# 用户行为数据(浏览、加购、购买)
behavior_records = []
for _ in range(5000):
user_id = np.random.randint(1, n_users + 1)
product_id = np.random.randint(1, n_products + 1)
behavior = np.random.choice(['浏览', '加购', '购买'], p=[0.6, 0.25, 0.15])
# 购买行为有金额
if behavior == '购买':
amount = product_data['price'][product_id - 1] * np.random.uniform(0.9, 1.1)
else:
amount = 0
behavior_records.append({
'user_id': user_id,
'product_id': product_id,
'behavior': behavior,
'amount': amount,
'timestamp': pd.Timestamp.now() - pd.Timedelta(days=np.random.randint(0, 365))
})
users = pd.DataFrame(user_data)
products = pd.DataFrame(product_data)
behaviors = pd.DataFrame(behavior_records)
print("=== 电商用户行为分析 ===")
print("\n用户数据:")
print(users.head())
print("\n商品数据:")
print(products.head())
print("\n行为数据:")
print(behaviors.head())
# 1. 用户基础分析
print("\n=== 用户基础分析 ===")
print(f"总用户数: {len(users)}")
print(f"用户年龄分布:\n{users['age'].describe()}")
print("\n性别分布:")
print(users['gender'].value_counts(normalize=True))
print("\n城市分布:")
print(users['city'].value_counts())
# 2. 行为分析
print("\n=== 行为分析 ===")
print("行为类型分布:")
behavior_counts = behaviors['behavior'].value_counts()
print(behavior_counts)
# 转化率分析
total_users = behaviors['user_id'].nunique()
browsed_users = behaviors[behaviors['behavior'] == '浏览']['user_id'].nunique()
purchased_users = behaviors[behaviors['behavior'] == '购买']['user_id'].nunique()
conversion_rate = purchased_users / browsed_users * 100
print(f"\n浏览用户数: {browsed_users}")
print(f"购买用户数: {purchased_users}")
print(f"转化率: {conversion_rate:.2f}%")
# 3. 销售分析
print("\n=== 销售分析 ===")
purchase_data = behaviors[behaviors['behavior'] == '购买']
print(f"总销售额: {purchase_data['amount'].sum():,.2f}")
print(f"平均订单金额: {purchase_data['amount'].mean():,.2f}")
print(f"订单数量: {len(purchase_data)}")
# 4. 用户价值分析(RFM模型简化版)
print("\n=== 用户价值分析 ===")
user_purchase = purchase_data.groupby('user_id').agg({
'amount': ['sum', 'count'],
'timestamp': 'max'
}).reset_index()
user_purchase.columns = ['user_id', '总消费', '购买次数', '最近购买']
# 计算R(最近购买天数)
current_date = pd.Timestamp.now()
user_purchase['R'] = (current_date - user_purchase['最近购买']).dt.days
# 分层
def user_segment(row):
if row['总消费'] > user_purchase['总消费'].quantile(0.8) and row['R'] < 30:
return '高价值'
elif row['总消费'] > user_purchase['总消费'].quantile(0.5) and row['R'] < 60:
return '中价值'
else:
return '低价值'
user_purchase['价值等级'] = user_purchase.apply(user_segment, axis=1)
print("用户价值分布:")
print(user_purchase['价值等级'].value_counts())
# 5. 商品分析
print("\n=== 商品分析 ===")
product_sales = purchase_data.groupby('product_id').agg({
'amount': 'sum',
'user_id': 'count'
}).reset_index()
product_sales.columns = ['product_id', '销售额', '购买次数']
product_sales = product_sales.merge(products, on='product_id')
print("畅销商品TOP10:")
print(product_sales.sort_values('销售额', ascending=False).head(10))
# 6. 类别分析
print("\n=== 类别分析 ===")
category_sales = product_sales.groupby('category')['销售额'].sum().sort_values(ascending=False)
print("各类别销售额:")
print(category_sales)
可视化分析
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 1. 用户年龄分布
plt.figure(figsize=(10, 6))
sns.histplot(data=users, x='age', bins=20, kde=True, color='steelblue')
plt.title('用户年龄分布', fontsize=16)
plt.xlabel('年龄', fontsize=12)
plt.ylabel('人数', fontsize=12)
plt.show()
# 2. 行为转化漏斗
plt.figure(figsize=(8, 6))
behavior_counts = behaviors['behavior'].value_counts()
sns.barplot(x=behavior_counts.index, y=behavior_counts.values, palette='viridis')
plt.title('用户行为分布', fontsize=16)
plt.xlabel('行为类型', fontsize=12)
plt.ylabel('次数', fontsize=12)
plt.show()
# 3. 销售趋势
plt.figure(figsize=(12, 6))
daily_sales = purchase_data.groupby(purchase_data['timestamp'].dt.date)['amount'].sum()
plt.plot(daily_sales.index, daily_sales.values, linewidth=1.5, alpha=0.8)
plt.title('日销售额趋势', fontsize=16)
plt.xlabel('日期', fontsize=12)
plt.ylabel('销售额', fontsize=12)
plt.xticks(rotation=45)
plt.show()
# 4. 用户价值分布
plt.figure(figsize=(8, 6))
value_counts = user_purchase['价值等级'].value_counts()
plt.pie(value_counts.values, labels=value_counts.index, autopct='%1.1f%%',
colors=sns.color_palette('pastel'))
plt.title('用户价值分布', fontsize=16)
plt.show()
# 5. 商品类别销售占比
plt.figure(figsize=(8, 8))
plt.pie(category_sales.values, labels=category_sales.index, autopct='%1.1f%%',
colors=sns.color_palette('Set3'))
plt.title('商品类别销售占比', fontsize=16)
plt.show()
# 6. 相关性分析
plt.figure(figsize=(8, 6))
# 合并用户和购买数据
user_purchase_full = user_purchase.merge(users, on='user_id')
correlation_data = user_purchase_full[['总消费', '购买次数', 'R', 'age']].corr()
sns.heatmap(correlation_data, annot=True, cmap='coolwarm', center=0, fmt='.2f')
plt.title('用户特征相关性', fontsize=16)
plt.show()
第五部分:性能优化与最佳实践
1. 内存优化技巧
import pandas as pd
import numpy as np
# 1. 优化数据类型
def optimize_memory(df):
"""优化DataFrame内存使用"""
df_optimized = df.copy()
for col in df_optimized.columns:
col_type = df_optimized[col].dtype
if col_type != object:
c_min = df_optimized[col].min()
c_max = df_optimized[col].max()
if str(col_type)[:3] == 'int':
if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
df_optimized[col] = df_optimized[col].astype(np.int8)
elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
df_optimized[col] = df_optimized[col].astype(np.int16)
elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
df_optimized[col] = df_optimized[col].astype(np.int32)
else:
if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
df_optimized[col] = df_optimized[col].astype(np.float16)
elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
df_optimized[col] = df_optimized[col].astype(np.float32)
return df_optimized
# 示例
large_df = pd.DataFrame({
'id': range(100000),
'value1': np.random.randint(0, 100, 100000),
'value2': np.random.randint(0, 1000, 100000),
'score': np.random.random(100000)
})
print("优化前内存使用:")
print(large_df.info(memory_usage='deep'))
optimized_df = optimize_memory(large_df)
print("\n优化后内存使用:")
print(optimized_df.info(memory_usage='deep'))
2. 向量化操作优化
# 避免使用循环,使用向量化操作
import time
# 创建大型数据集
n = 1000000
df = pd.DataFrame({
'a': np.random.random(n),
'b': np.random.random(n)
})
# 方法1:循环(慢)
def calc_loop(df):
result = []
for i in range(len(df)):
if df.loc[i, 'a'] > 0.5:
result.append(df.loc[i, 'a'] + df.loc[i, 'b'])
else:
result.append(df.loc[i, 'a'] - df.loc[i, 'b'])
return result
# 方法2:向量化(快)
def calc_vectorized(df):
return np.where(df['a'] > 0.5, df['a'] + df['b'], df['a'] - df['b'])
# 方法3:使用apply(中等)
def calc_apply(df):
return df.apply(lambda row: row['a'] + row['b'] if row['a'] > 0.5 else row['a'] - row['b'], axis=1)
# 性能对比
start = time.time()
result1 = calc_loop(df)
time1 = time.time() - start
start = time.time()
result2 = calc_vectorized(df)
time2 = time.time() - start
start = time.time()
result3 = calc_apply(df)
time3 = time.time() - start
print(f"循环方式耗时: {time1:.4f}秒")
print(f"向量化方式耗时: {time2:.4f}秒")
print(f"apply方式耗时: {time3:.4f}秒")
print(f"向量化比循环快: {time1/time2:.1f}倍")
3. 大数据处理技巧
# 处理大数据集时使用chunksize
def process_large_csv(file_path):
"""分块读取处理大文件"""
chunks = pd.read_csv(file_path, chunksize=10000)
results = []
for chunk in chunks:
# 对每个块进行处理
chunk_result = chunk.groupby('category')['sales'].sum()
results.append(chunk_result)
# 合并结果
final_result = pd.concat(results).groupby(level=0).sum()
return final_result
# 使用query方法进行高效筛选
def efficient_filter(df):
"""使用query进行高效筛选"""
# 慢:df[(df['a'] > 0.5) & (df['b'] < 0.8) & (df['c'] == 'value')]
# 快:
return df.query('a > 0.5 and b < 0.8 and c == "value"')
# 使用eval进行高效计算
def efficient_calc(df):
"""使用eval进行高效计算"""
# 慢:df['result'] = df['a'] * df['b'] + df['c'] - df['d']
# 快:
df.eval('result = a * b + c - d', inplace=True)
return df
4. 代码组织与模块化
# 推荐的数据分析项目结构
"""
project/
├── data/
│ ├── raw/ # 原始数据
│ └── processed/ # 处理后数据
├── src/
│ ├── __init__.py
│ ├── data_loader.py # 数据加载
│ ├── data_cleaner.py # 数据清洗
│ ├── analyzer.py # 分析函数
│ └── visualizer.py # 可视化函数
├── notebooks/
│ └── analysis.ipynb # 分析笔记本
├── requirements.txt
└── README.md
"""
# 示例:创建一个分析模块
# src/analyzer.py
class SalesAnalyzer:
"""销售数据分析器"""
def __init__(self, data):
self.data = data
def get_monthly_sales(self):
"""获取月度销售额"""
return self.data.groupby(
self.data['日期'].dt.to_period('M')
)['销售额'].sum()
def get_top_products(self, n=10):
"""获取畅销商品"""
return self.data.groupby('产品')['销售额'].sum().nlargest(n)
def get_conversion_rate(self):
"""计算转化率"""
total = self.data['user_id'].nunique()
buyers = self.data[self.data['behavior'] == '购买']['user_id'].nunique()
return buyers / total * 100
# 使用示例
# from src.analyzer import SalesAnalyzer
# analyzer = SalesAnalyzer(sales_df)
# monthly = analyzer.get_monthly_sales()
第六部分:职场应用与职业发展建议
1. 常见职场场景解决方案
场景1:快速生成周报
def generate_weekly_report(df, week_start):
"""快速生成周报"""
week_end = week_start + pd.Timedelta(days=6)
week_data = df[(df['日期'] >= week_start) & (df['日期'] <= week_end)]
report = {
'周期': f"{week_start} 至 {week_end}",
'总销售额': week_data['销售额'].sum(),
'订单数': len(week_data),
'平均客单价': week_data['销售额'].sum() / len(week_data),
'热销产品': week_data.groupby('产品')['销售额'].sum().nlargest(3).index.tolist()
}
return report
场景2:异常数据自动检测
def detect_anomalies(df, column, threshold=3):
"""使用Z-score检测异常值"""
z_scores = np.abs((df[column] - df[column].mean()) / df[column].std())
anomalies = df[z_scores > threshold]
return anomalies
场景3:A/B测试分析
def ab_test_analysis(control, treatment):
"""A/B测试分析"""
from scipy import stats
# 计算统计显著性
t_stat, p_value = stats.ttest_ind(control, treatment)
result = {
'控制组均值': control.mean(),
'实验组均值': treatment.mean(),
'提升百分比': (treatment.mean() - control.mean()) / control.mean() * 100,
'p值': p_value,
'显著': p_value < 0.05
}
return result
2. 提升职场竞争力的建议
建立个人作品集
- 在GitHub上创建数据分析项目
- 撰写技术博客分享解决方案
- 参与Kaggle竞赛
持续学习
- 关注Python数据分析领域的最新发展
- 学习机器学习、深度学习等进阶技能
- 掌握SQL、Spark等大数据工具
提升业务理解
- 理解所在行业的业务逻辑
- 学会用数据驱动业务决策
- 培养数据讲故事的能力
软技能提升
- 提高沟通能力,能向非技术人员解释分析结果
- 学会项目管理,高效推进数据分析项目
- 培养商业敏感度,发现数据背后的商业机会
3. 简历与面试准备
简历中应该突出的技能点:
- 熟练使用Python进行数据清洗、分析和可视化
- 掌握pandas、numpy、matplotlib/seaborn等核心库
- 具备实际项目经验,能独立完成数据分析全流程
- 熟悉统计学基础和机器学习算法
面试常见问题准备:
- 如何处理缺失值和异常值?
- 如何优化pandas代码性能?
- 如何设计一个数据分析项目?
- 如何向业务部门解释分析结果?
总结
通过本课程的学习,你已经系统掌握了Python数据分析的核心技能:
- NumPy:高效数值计算的基础,向量化操作提升性能
- Pandas:强大的数据处理能力,从清洗到高级分析
- 可视化:用图表让数据说话,提升报告说服力
- 实战应用:解决真实业务问题,创造商业价值
- 性能优化:处理大数据,提升工作效率
- 职场应用:将技能转化为职业竞争力
记住,数据分析不仅仅是写代码,更重要的是:
- 理解业务:数据背后的故事
- 解决问题:用数据驱动决策
- 持续学习:技术日新月异,保持好奇心
- 沟通表达:让非技术人员理解你的发现
现在,你已经具备了从入门到精通的完整知识体系。接下来就是不断实践,在真实项目中磨练技能,最终成为数据分析领域的专家!
下一步行动建议:
- 找一个你感兴趣的数据集进行实战练习
- 在工作中寻找可以自动化的数据分析任务
- 参与开源项目或Kaggle竞赛
- 持续学习新的库和工具(如Polars、Dask等)
- 建立个人品牌,分享你的数据分析成果
祝你在数据分析的道路上越走越远,职场竞争力不断提升!
