目录
[1.1 数据读取与写入](#1.1 数据读取与写入)
[1.2 数据探索与清洗](#1.2 数据探索与清洗)
[1.3 数据转换与聚合](#1.3 数据转换与聚合)
[1.4 时间序列处理](#1.4 时间序列处理)
[2.1 数组操作](#2.1 数组操作)
[2.2 数学运算](#2.2 数学运算)
[2.3 线性代数](#2.3 线性代数)
[2.4 广播机制](#2.4 广播机制)
[三、Pandas 与 NumPy 的协同工作](#三、Pandas 与 NumPy 的协同工作)
[3.1 数据结构转换](#3.1 数据结构转换)
[3.2 性能优化](#3.2 性能优化)
[4.1 数据准备与加载](#4.1 数据准备与加载)
[4.2 核心分析:用户行为漏斗与价值分析](#4.2 核心分析:用户行为漏斗与价值分析)
[4.3 可视化呈现:洞察的直观表达](#4.3 可视化呈现:洞察的直观表达)
[5.1 性能优化技巧](#5.1 性能优化技巧)
[5.2 代码规范与可维护性](#5.2 代码规范与可维护性)
前言:数据科学的双引擎
在 Python 数据科学领域,Pandas 和 NumPy 就像一对黄金搭档,共同构成了数据处理与科学计算的核心基础。NumPy 提供了高效的数组操作和数学函数,而 Pandas 则基于 NumPy 构建了更高级的数据结构和数据处理工具。本文将系统梳理这两个库的高频功能,通过场景化示例帮助读者快速掌握实战技能。
一、Pandas
1.1 数据读取与写入
Pandas 支持从多种格式读取数据,同时能将处理结果输出到不同介质,形成完整的数据流转闭环。
- pd.read_csv()
- pd.read_excel()
- pd.read_jason()
- pd.read_sql()
python
import pandas as pd
# 读取不同格式数据
df_csv = pd.read_csv('sales_data.csv') # 最常用的CSV格式
df_excel = pd.read_excel('财务报表.xlsx', sheet_name='XXXX年数据') # 多sheet处理
df_json = pd.read_json('用户行为.json') # 半结构化数据处理
df_sql = pd.read_sql('SELECT * FROM user_table WHERE age > 18', conn) # 数据库交互
- df.to_csv()
- df.to_excel()
- dfto_jason()
python
# 数据写出(注意index=False避免写入索引列)
df_csv.to_csv('清洗后数据.csv', index=False)
df_excel.to_excel('汇总报表.xlsx', sheet_name='分析结果', index=False)
df_json.to_json('格式化数据.json', orient='records') # orient参数控制输出结构
应用场景:
-
日常业务中,从 CSV 读取日志数据进行分析
-
财务场景中处理多 sheet 的 Excel 报表
-
爬虫项目中解析 JSON 格式的 API 返回结果
1.2 数据探索与清洗
数据清洗是数据分析的前置条件,Pandas 提供了一套完整的工具链来探查数据质量并修复问题。
- df.info()
- df.describe()
python
# 数据概览(快速了解数据结构)
print(f"数据维度: {df.shape}") # (行数, 列数)
print(df.info()) # 查看各列数据类型和非空值情况
print(df.describe()) # 数值列的统计摘要
- df.fillna()
- df.dropna()
python
# 缺失值处理(三种策略:删除、填充、标记)
print("缺失值统计:\n", df.isnull().sum()) # 统计每列缺失值
df_clean = df.fillna({
'数值列': df['数值列'].median(), # 用中位数填充数值列
'分类列': '未知类别', # 用默认值填充分类列
'时间列': pd.NaT # 标记时间类型缺失
})
df_clean = df_clean.dropna(subset=['关键列']) # 仅删除关键列有缺失的行
python
# 异常值处理(Z-score方法)
from scipy import stats
z_scores = np.abs(stats.zscore(df['销售额']))
df_normal = df[z_scores < 3] # 过滤Z-score绝对值大于3的异常值
1.3 数据转换与聚合
数据转换是将原始数据转化为分析所需形式的关键步骤,Pandas 提供了灵活的转换机制。
python
# 列派生(三种创建新列的方式)
df['年度销售额'] = df['月销售额'] * 12 # 直接计算
# 函数映射
df['消费等级'] = df['消费金额'].apply(
lambda x: '高消费' if x > 1000 else '中消费' if x > 500 else '低消费')
# 向量化条件判断
df['促销标签'] = np.where(
df['购买日期'].dt.month.isin([11, 12]), '促销季', '常规季')
python
# 分组聚合(数据汇总的核心功能)
dept_sales = df.groupby('部门')['销售额'].sum() # 单分组单指标
dept_analysis = df.groupby('部门').agg(
平均销售额=('销售额', 'mean'),
最大订单=('订单金额', 'max'),
有效客户=('客户ID', 'nunique') # 去重计数
) # 多指标聚合+重命名列
- pd.pivot_table()
python
# 透视表(二维数据汇总)
pivot_table = pd.pivot_table(
df,
index='地区',
columns='产品类别',
values='销售额',
aggfunc='sum'
) # 类似Excel透视表的强大功能
1.4 时间序列处理
时间序列数据在金融、物联网、日志分析等场景中极为常见,Pandas 提供了专业的处理工具。
python
# 时间格式标准化
df['交易时间'] = pd.to_datetime(df['交易时间'], format='%Y-%m-%d %H:%M:%S') # 解析多种格式
df.set_index('交易时间', inplace=True) # 将时间列设为索引
# 时间特征提取
df['年份'] = df.index.year
df['季度'] = df.index.quarter
df['星期几'] = df.index.dayofweek # 0-6表示周一到周日
df['是否工作日'] = ~df.index.dayofweek.isin([5, 6]) # 周末判断
# 时间序列重采样(将高频数据聚合为低频)
daily_sales = df['销售额']
monthly_sum = daily_sales.resample('M').sum() # 按月求和
weekly_avg = daily_sales.resample('W').mean() # 按周求平均
# 时间窗口操作
daily_sales['7日移动平均'] = daily_sales.rolling(window=7).mean() # 短期趋势
daily_sales['30日移动平均'] = daily_sales.rolling(window=30).mean() # 中期趋势
二、NumPy
2.1 数组操作
NumPy 的ndarray数组是其所有功能的基础,相比 Python 列表具有更高的内存效率和计算速度。
python
import numpy as np
# 数组创建(多种创建方式)
arr_from_list = np.array([1, 3, 5, 7]) # 从列表创建
zeros_arr = np.zeros((3, 4)) # 全0数组
ones_arr = np.ones((2, 3), dtype=int) # 全1数组(指定类型)
eye_arr = np.eye(3) # 单位矩阵
rand_arr = np.random.rand(2, 2) # [0,1)均匀分布随机数
# 数组操作(形状与属性)
print(f"数组形状: {rand_arr.shape}") # (2, 2)
print(f"维度数量: {rand_arr.ndim}") # 2
print(f"元素类型: {rand_arr.dtype}") # float64
reshaped = rand_arr.reshape(4, 1) # 改变形状但不改变数据
flattened = rand_arr.flatten() # 展平为一维数组
transposed = rand_arr.T # 矩阵转置
# 数组连接与分割
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
vstack = np.vstack((a, b)) # 垂直堆叠
hstack = np.hstack((a, b)) # 水平堆叠
split_arr = np.split(hstack, 2, axis=1) # 按列分割
性能优势:
-
数组操作是向量化的,避免 Python 循环的性能损耗
-
连续内存布局使得 CPU 缓存利用率更高
-
支持 BLAS/LAPACK 等底层优化库,提升计算速度
2.2 数学运算
NumPy 将大量数学函数向量化,实现了高效的数值计算。
python
# 基本算术运算(逐元素操作)
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
add = a + b # [5, 7, 9]
sub = a - b # [-3, -3, -3]
mul = a * b # [4, 10, 18]
div = a / b # [0.25, 0.4, 0.5]
# 矩阵运算(线性代数基础)
mat_a = np.array([[1, 2], [3, 4]])
mat_b = np.array([[5, 6], [7, 8]])
dot_product = np.dot(mat_a, mat_b) # 矩阵乘法
# 等价于 mat_a @ mat_b(Python 3.5+支持)
# 统计函数(数据描述)
data = np.array([12, 15, 18, 21, 24])
print(f"总和: {np.sum(data)}") # 90
print(f"均值: {np.mean(data)}") # 18.0
print(f"中位数: {np.median(data)}") # 18.0
print(f"标准差: {np.std(data):.2f}") # 4.24
print(f"最大值索引: {np.argmax(data)}") # 4(对应24)
# 条件运算(向量化条件判断)
arr = np.array([-2, 0, 3, -5, 7])
positive = np.where(arr > 0, arr, 0) # [0, 0, 3, 0, 7]
mask = arr % 2 == 0 # 偶数掩码
even_numbers = arr[mask] # [ -2, 0]
2.3 线性代数
NumPy 的线性代数模块提供了矩阵运算的核心功能,是机器学习算法的底层支持。
python
# 矩阵基本运算
mat = np.array([[1, 2], [3, 4]])
inv_mat = np.linalg.inv(mat) # 矩阵求逆
det_mat = np.linalg.det(mat) # 行列式计算
eig_vals, eig_vecs = np.linalg.eig(mat) # 特征值与特征向量
# 线性方程组求解 Ax = b
A = np.array([[2, 1], [1, 2]])
b = np.array([3, 3])
x = np.linalg.solve(A, b) # 解为 [1, 1]
# 奇异值分解(SVD)
U, S, Vh = np.linalg.svd(mat) # 矩阵分解
# 范数计算
norm_1 = np.linalg.norm(mat, ord=1) # 列范数(绝对值列和最大值)
norm_inf = np.linalg.norm(mat, ord=np.inf) # 行范数(绝对值行和最大值)
2.4 广播机制
NumPy 的广播机制允许不同形状的数组进行运算,是其灵活性和高效性的重要体现。
python
# 广播示例1:向量与标量运算
a = np.array([1, 2, 3])
b = 2
result = a + b # [3, 4, 5],标量广播到每个元素
# 广播示例2:二维数组与一维数组运算
matrix = np.array([[1, 2, 3], [4, 5, 6]])
vector = np.array([10, 20, 30])
# vector被广播为[[10,20,30],[10,20,30]]
broadcast_result = matrix + vector # 等价于:
# [[1+10, 2+20, 3+30],
# [4+10, 5+20, 6+30]]
# 广播规则示意图
# matrix形状: (2, 3)
# vector形状: (3,) → 广播为 (2, 3)
# 结果形状: (2, 3)
# 广播示例3:不同维度数组运算
arr_3d = np.zeros((3, 4, 5))
arr_2d = np.ones((4, 5))
sum_result = arr_3d + arr_2d # 沿第一个维度广播
广播规则:
-
从后往前比较各维度大小
-
维度大小为 1 或相等时可以广播
-
维度大小不同时,将较小的维度扩展为较大的维度大小
-
广播会隐式创建虚拟副本,不实际占用内存
三、Pandas 与 NumPy 的协同工作
3.1 数据结构转换
Pandas 的数据结构本质上是对 NumPy 数组的封装,两者可以自由转换。
python
# Pandas到NumPy
df = pd.DataFrame({
'A': [1, 2, 3],
'B': [4, 5, 6]
})
numpy_array = df.values # 将DataFrame转为NumPy数组
series_array = df['A'].to_numpy() # 将Series转为NumPy数组
# NumPy到Pandas
new_df = pd.DataFrame(numpy_array, columns=['X', 'Y']) # 数组转DataFrame
new_series = pd.Series(series_array, name='数值列') # 数组转Series
# 混合使用示例
# 用NumPy生成随机数据,再用Pandas处理
random_data = np.random.randn(100, 3)
df = pd.DataFrame(
random_data,
columns=['特征1', '特征2', '目标值']
)
# 使用Pandas进行数据清洗
cleaned_data = df.dropna()
# 再用NumPy进行数值计算
mean_values = np.mean(cleaned_data.values, axis=0)
3.2 性能优化
在实际项目中,合理结合 Pandas 和 NumPy 可以大幅提升性能。
python
# 案例:大型数据的分组统计优化
# 传统Pandas方法(较慢)
def pandas_method(df):
return df.groupby('分组列')['数值列'].sum()
# 优化方法:先转NumPy再分组(更快)
def numpy_optimized(df):
groups = df['分组列'].to_numpy()
values = df['数值列'].to_numpy()
unique_groups = np.unique(groups)
results = np.zeros_like(unique_groups, dtype=float)
for i, group in enumerate(unique_groups):
results[i] = np.sum(values[groups == group])
return pd.Series(results, index=unique_groups, name='数值列_sum')
# 性能对比(数据量越大优势越明显)
large_df = pd.DataFrame({
'分组列': np.random.choice(1000, size=1000000),
'数值列': np.random.randn(1000000)
})
%timeit pandas_method(large_df) # 传统方法耗时较长
%timeit numpy_optimized(large_df) # 优化方法耗时显著减少
优化原则:
-
对不需要索引的数据,转为 NumPy 数组处理更高效
-
复杂的数值计算尽量使用 NumPy 向量化操作
-
大型数据的分组聚合可考虑 NumPy 的直接计算
-
涉及矩阵运算时优先使用 NumPy 的线性代数函数
四、实战案例:电商用户行为分析
4.1 数据准备与加载
python
# 假设我们有电商用户行为数据
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 模拟生成数据(实际项目中从文件读取)
np.random.seed(42) # 保证结果可复现
n_samples = 10000
# 生成基础数据
user_ids = np.random.randint(1000, 9999, n_samples)
item_ids = np.random.randint(100, 999, n_samples)
timestamps = pd.date_range('2024-01-01', '2024-12-31', periods=n_samples)
actions = np.random.choice(['浏览', '加购', '下单', '支付'], n_samples)
prices = np.random.normal(100, 50, n_samples).clip(10, 500).astype(int)
# 创建DataFrame
df = pd.DataFrame({
'用户ID': user_ids,
'商品ID': item_ids,
'时间戳': timestamps,
'行为类型': actions,
'价格': prices
})
# 数据预处理
df['月份'] = df['时间戳'].dt.month
df['是否促销月'] = df['月份'].isin([6, 11]) # 假设618和双11是促销月
4.2 核心分析:用户行为漏斗与价值分析
python
# 1. 构建用户行为漏斗
funnel = df.groupby(['用户ID', '行为类型'])['商品ID'].count().unstack(fill_value=0)
# 计算各行为转化率
funnel['浏览-加购转化率'] = funnel['加购'] / funnel['浏览']
funnel['加购-下单转化率'] = funnel['下单'] / funnel['加购']
funnel['下单-支付转化率'] = funnel['支付'] / funnel['下单']
# 2. 计算用户价值(RFM模型)
# 最近消费(Recency):最后一次消费距离今天的天数
rfm = df.groupby('用户ID')['时间戳'].max().reset_index()
rfm['最近消费天数'] = (pd.Timestamp('2024-12-31') - rfm['时间戳']).dt.days
# 消费频率(Frequency):统计下单次数
freq = df[df['行为类型'] == '下单'].groupby('用户ID')['行为类型'].count().reset_index()
freq.columns = ['用户ID', '消费频率']
rfm = pd.merge(rfm, freq, on='用户ID', how='left').fillna(0)
# 消费金额(Monetary):统计消费总额
monetary = df[df['行为类型'] == '支付'].groupby('用户ID')['价格'].sum().reset_index()
monetary.columns = ['用户ID', '消费金额']
rfm = pd.merge(rfm, monetary, on='用户ID', how='left').fillna(0)
# 3. 促销月效果分析
promotion_effect = df.groupby(['是否促销月', '行为类型'])['商品ID'].count().unstack()
promotion_effect['行为增长比'] = promotion_effect[True] / promotion_effect[False] - 1
4.3 可视化呈现:洞察的直观表达
python
# 1. 月度销售趋势
monthly_sales = df[df['行为类型'] == '支付'].groupby('月份')['价格'].sum()
plt.figure(figsize=(12, 6))
plt.plot(monthly_sales.index, monthly_sales.values, marker='o', color='blue')
plt.title('2024年月度销售总额趋势')
plt.xlabel('月份')
plt.ylabel('销售总额(元)')
plt.grid(True, linestyle='--', alpha=0.7)
plt.xticks(monthly_sales.index)
plt.tight_layout()
# 2. 用户价值分布
plt.figure(figsize=(15, 5))
plt.subplot(1, 3, 1)
plt.hist(rfm['最近消费天数'], bins=20, color='green', alpha=0.7)
plt.title('用户最近消费天数分布')
plt.xlabel('距离最后消费的天数')
plt.ylabel('用户数')
plt.subplot(1, 3, 2)
plt.hist(rfm['消费频率'], bins=20, color='orange', alpha=0.7)
plt.title('用户消费频率分布')
plt.xlabel('消费次数')
plt.ylabel('用户数')
plt.subplot(1, 3, 3)
plt.hist(rfm['消费金额'], bins=20, color='red', alpha=0.7)
plt.title('用户消费金额分布')
plt.xlabel('消费总额(元)')
plt.ylabel('用户数')
plt.tight_layout()
# 3. 促销月行为增长
promotion_effect['行为增长比'].plot(kind='bar', color='purple', alpha=0.8)
plt.title('促销月各行为增长比例')
plt.ylabel('增长倍数')
plt.axhline(y=0, color='k', linestyle='-')
plt.tight_layout()
五、进阶技巧与最佳实践
5.1 性能优化技巧
1、向量化操作优先:
避免使用 Python 循环,尽量用 Pandas 的apply()或 NumPy 的向量化函数替代
2、数据类型优化:
使用df.astype()将数值列转为合适的类型(如int8替代int64)
3、内存映射文件:
处理大型数据时使用pd.read_csv(..., chunksize=...)分块读取
4、NumPy 数组替代:
对纯数值计算,将 Pandas 数据转为 NumPy 数组处理更高效
5.2 代码规范与可维护性
1、函数封装:
将常用数据处理流程封装为函数,如data_cleaning()、feature_engineering()
2、文档字符串:
为关键函数添加 Google 风格文档字符串,说明参数、返回值和示例
3、项目结构:
按功能模块组织代码,如data_loader.py、data_analyzer.py
4、版本控制:
使用 Git 管理代码版本,重要节点添加清晰的提交说明
六、总结
掌握 Pandas 和 NumPy 不仅是学会两个 Python 库的使用,更是培养数据思维和科学计算思维的过程:
Pandas教会如何:
处理结构化数据的清洗、转换与分析,构建数据处理的完整流程
NumPy教会如何:
进行高效的数值计算,理解向量化思维和矩阵运算的数学本质
在实际数据科学项目中,这两个库通常与 Matplotlib(可视化)、Scikit-learn(机器学习)等库配合使用,形成完整的技术栈。