第12章 数据科学与分析实战¶
12.1 数据科学基础¶
12.1.1 数据科学概述¶
数据科学是一个跨学科领域,它使用科学方法、过程、算法和系统从结构化和非结构化数据中提取知识和洞察。数据科学的核心目标是通过数据驱动的方法来解决实际问题,为决策提供支持。
数据科学的重要性:
- 商业价值:帮助企业发现新的商业机会,优化运营效率
- 科学研究:加速科学发现,验证假设
- 社会影响:改善医疗、教育、交通等公共服务
- 个人决策:为个人提供个性化的服务和建议
数据科学工作流程:
1. 问题定义:明确要解决的业务问题
2. 数据收集:获取相关的数据源
3. 数据清洗:处理缺失值、异常值和不一致的数据
4. 探索性数据分析:理解数据的分布和特征
5. 特征工程:创建和选择有用的特征
6. 模型建立:选择合适的算法建立预测模型
7. 模型评估:验证模型的性能和可靠性
8. 结果解释:将分析结果转化为可行的建议
数据类型和特征:
- 结构化数据:表格形式的数据,如CSV、数据库表
- 半结构化数据:JSON、XML等格式的数据
- 非结构化数据:文本、图像、音频、视频等
- 数值型数据:连续型(身高、体重)和离散型(年龄、数量)
- 分类型数据:名义型(颜色、性别)和有序型(教育程度、满意度)
12.1.2 Python在数据科学中的优势¶
Python之所以成为数据科学的首选语言,主要有以下几个原因:
丰富的数据处理库:
- NumPy:提供高性能的多维数组对象和数学函数
- Pandas:强大的数据分析和操作工具
- SciPy:科学计算库,包含统计、优化、信号处理等功能
- Scikit-learn:机器学习库,提供各种算法实现
强大的可视化工具:
- Matplotlib:基础绘图库,功能全面
- Seaborn:基于Matplotlib的统计可视化库
- Plotly:交互式可视化库
- Bokeh:Web可视化库
机器学习生态系统:
- TensorFlow:Google开发的深度学习框架
- PyTorch:Facebook开发的深度学习框架
- XGBoost:梯度提升算法库
- LightGBM:微软开发的梯度提升框架
12.1.3 数据科学环境搭建¶
为了高效地进行数据科学工作,我们需要搭建一个完整的开发环境。推荐使用Anaconda,它是一个Python数据科学平台,包含了大部分常用的库。
安装Anaconda:
- 访问Anaconda官网下载适合你操作系统的版本
- 运行安装程序,按照提示完成安装
- 验证安装是否成功:
conda --version
输出类似如下:
conda 23.7.4
创建数据科学环境:
# 创建新的conda环境
conda create -n datascience python=3.9
# 激活环境
conda activate datascience
# 安装核心数据科学库
conda install numpy pandas matplotlib seaborn scikit-learn jupyter
启动Jupyter Notebook:
jupyter notebook
12.1.4 数据科学项目结构¶
一个良好的项目结构对于数据科学项目的成功至关重要。以下是推荐的项目组织方式:
data_science_project/
├── data/
│ ├── raw/ # 原始数据
│ ├── processed/ # 处理后的数据
│ └── external/ # 外部数据源
├── notebooks/ # Jupyter notebooks
│ ├── 01_data_exploration.ipynb
│ ├── 02_data_cleaning.ipynb
│ └── 03_modeling.ipynb
├── src/ # 源代码
│ ├── data/ # 数据处理脚本
│ ├── features/ # 特征工程
│ ├── models/ # 模型相关代码
│ └── visualization/ # 可视化代码
├── models/ # 训练好的模型
├── reports/ # 分析报告
│ ├── figures/ # 图表
│ └── final_report.md # 最终报告
├── requirements.txt # 依赖包列表
├── README.md # 项目说明
└── config.py # 配置文件
12.2 NumPy数值计算¶
NumPy(Numerical Python)是Python数据科学生态系统的基础库,它提供了高性能的多维数组对象和用于处理这些数组的工具。NumPy的核心是ndarray对象,它是一个快速且节省空间的多维数组,提供了向量化的数学运算。
12.2.1 NumPy基础¶
导入NumPy:
import numpy as np
print(f"NumPy版本: {np.__version__}")
数组(ndarray)概念:
NumPy数组是一个由相同类型元素组成的多维容器。与Python列表相比,NumPy数组具有以下优势:
- 性能更高:底层用C语言实现,运算速度快
- 内存效率:元素类型相同,内存布局紧凑
- 向量化运算:支持对整个数组进行数学运算
- 广播机制:不同形状的数组可以进行运算
数组创建方法:
# 从Python列表创建数组
arr1 = np.array([1, 2, 3, 4, 5])
print(f"一维数组: {arr1}")
print(f"数组类型: {type(arr1)}")
print(f"数组形状: {arr1.shape}")
print(f"数组维度: {arr1.ndim}")
# 创建二维数组
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print(f"\n二维数组:\n{arr2}")
print(f"数组形状: {arr2.shape}")
print(f"数组维度: {arr2.ndim}")
# 使用内置函数创建数组
zeros = np.zeros((3, 4)) # 创建3x4的零数组
ones = np.ones((2, 3)) # 创建2x3的一数组
eye = np.eye(3) # 创建3x3的单位矩阵
arange = np.arange(0, 10, 2) # 创建等差数列
linspace = np.linspace(0, 1, 5) # 创建等间距数列
print(f"\n零数组:\n{zeros}")
print(f"\n一数组:\n{ones}")
print(f"\n单位矩阵:\n{eye}")
print(f"\n等差数列: {arange}")
print(f"等间距数列: {linspace}")
12.2.2 数组操作¶
数组索引和切片:
# 创建测试数组
arr = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]])
print(f"原始数组:\n{arr}")
# 基本索引
print(f"\n第一行: {arr[0]}")
print(f"第一行第二列: {arr[0, 1]}")
print(f"最后一个元素: {arr[-1, -1]}")
# 切片操作
print(f"\n前两行: \n{arr[:2]}")
print(f"前两行前三列: \n{arr[:2, :3]}")
print(f"所有行的第二列: {arr[:, 1]}")
print(f"每隔一行: \n{arr[::2]}")
# 布尔索引
mask = arr > 6
print(f"\n大于6的元素掩码:\n{mask}")
print(f"大于6的元素: {arr[mask]}")
# 花式索引
indices = [0, 2] # 选择第0行和第2行
print(f"\n选择第0行和第2行:\n{arr[indices]}")
数组形状操作:
# 创建测试数组
arr = np.arange(12)
print(f"原始数组: {arr}")
print(f"原始形状: {arr.shape}")
# 改变形状
reshaped = arr.reshape(3, 4)
print(f"\n重塑为3x4:\n{reshaped}")
# 转置
transposed = reshaped.T
print(f"\n转置后:\n{transposed}")
# 展平
flattened = reshaped.flatten()
print(f"\n展平后: {flattened}")
# 添加维度
expanded = np.expand_dims(arr, axis=0)
print(f"\n添加维度后形状: {expanded.shape}")
print(f"添加维度后:\n{expanded}")
# 压缩维度
squeezed = np.squeeze(expanded)
print(f"\n压缩维度后形状: {squeezed.shape}")
print(f"压缩维度后: {squeezed}")
12.2.3 数学运算¶
元素级运算:
# 创建测试数组
a = np.array([1, 2, 3, 4])
b = np.array([5, 6, 7, 8])
print(f"数组a: {a}")
print(f"数组b: {b}")
# 基本算术运算
print(f"\n加法: {a + b}")
print(f"减法: {a - b}")
print(f"乘法: {a * b}")
print(f"除法: {a / b}")
print(f"幂运算: {a ** 2}")
print(f"取余: {b % a}")
# 比较运算
print(f"\n大于: {a > 2}")
print(f"等于: {a == b}")
print(f"小于等于: {a <= 3}")
# 数学函数
print(f"\n平方根: {np.sqrt(a)}")
print(f"指数: {np.exp(a)}")
print(f"对数: {np.log(a)}")
print(f"正弦: {np.sin(a)}")
print(f"绝对值: {np.abs(a - 5)}")
广播机制:
# 广播示例
a = np.array([[1, 2, 3],
[4, 5, 6]])
b = np.array([10, 20, 30])
c = np.array([[100],
[200]])
print(f"数组a (2x3):\n{a}")
print(f"数组b (3,): {b}")
print(f"数组c (2x1):\n{c}")
# 广播运算
print(f"\na + b (广播):\n{a + b}")
print(f"\na + c (广播):\n{a + c}")
print(f"\nb * c (广播):\n{b * c}")
# 标量广播
print(f"\na * 10 (标量广播):\n{a * 10}")
聚合函数:
# 创建测试数组
arr = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]])
print(f"原始数组:\n{arr}")
# 基本聚合函数
print(f"\n总和: {np.sum(arr)}")
print(f"平均值: {np.mean(arr)}")
print(f"标准差: {np.std(arr)}")
print(f"方差: {np.var(arr)}")
print(f"最小值: {np.min(arr)}")
print(f"最大值: {np.max(arr)}")
print(f"中位数: {np.median(arr)}")
# 按轴聚合
print(f"\n按行求和 (axis=1): {np.sum(arr, axis=1)}")
print(f"按列求和 (axis=0): {np.sum(arr, axis=0)}")
print(f"按行求平均 (axis=1): {np.mean(arr, axis=1)}")
print(f"按列求平均 (axis=0): {np.mean(arr, axis=0)}")
# 累积函数
print(f"\n累积和: {np.cumsum(arr.flatten())}")
print(f"累积积: {np.cumprod([1, 2, 3, 4, 5])}")
# 位置函数
print(f"\n最小值位置: {np.argmin(arr)}")
print(f"最大值位置: {np.argmax(arr)}")
print(f"按行最小值位置: {np.argmin(arr, axis=1)}")
print(f"按列最大值位置: {np.argmax(arr, axis=0)}")
12.2.4 高级功能¶
条件选择和布尔索引:
# 创建测试数据
np.random.seed(42)
data = np.random.randn(10)
print(f"随机数据: {data}")
# 条件选择
positive = data[data > 0]
negative = data[data < 0]
print(f"\n正数: {positive}")
print(f"负数: {negative}")
# 多条件选择
moderate = data[(data > -1) & (data < 1)]
print(f"绝对值小于1的数: {moderate}")
# 使用where函数
result = np.where(data > 0, data, 0) # 正数保持,负数变为0
print(f"\n正数保持,负数变0: {result}")
# 条件计数
positive_count = np.sum(data > 0)
negative_count = np.sum(data < 0)
print(f"\n正数个数: {positive_count}")
print(f"负数个数: {negative_count}")
# 二维数组的条件选择
matrix = np.random.randint(1, 10, (3, 4))
print(f"\n随机矩阵:\n{matrix}")
print(f"大于5的元素: {matrix[matrix > 5]}")
print(f"大于5的位置: {np.where(matrix > 5)}")
排序和搜索:
# 创建测试数据
np.random.seed(42)
arr = np.random.randint(1, 20, 10)
print(f"原始数组: {arr}")
# 排序
sorted_arr = np.sort(arr)
print(f"排序后: {sorted_arr}")
# 获取排序索引
sort_indices = np.argsort(arr)
print(f"排序索引: {sort_indices}")
print(f"通过索引排序: {arr[sort_indices]}")
# 部分排序(获取最小的k个元素)
partial_sort = np.partition(arr, 3) # 第3小的元素及其左边的元素
print(f"部分排序: {partial_sort}")
# 二维数组排序
matrix = np.random.randint(1, 10, (3, 4))
print(f"\n原始矩阵:\n{matrix}")
print(f"按行排序:\n{np.sort(matrix, axis=1)}")
print(f"按列排序:\n{np.sort(matrix, axis=0)}")
# 搜索
sorted_arr = np.array([1, 3, 5, 7, 9, 11, 13, 15])
print(f"\n有序数组: {sorted_arr}")
print(f"搜索值7的位置: {np.searchsorted(sorted_arr, 7)}")
print(f"搜索值8应插入的位置: {np.searchsorted(sorted_arr, 8)}")
print(f"搜索多个值: {np.searchsorted(sorted_arr, [4, 8, 12])}")
随机数生成:
```python
设置随机种子¶
np.random.seed(42)
基本随机数生成¶
print(f”0-1之间的随机数: {np.random.random(5)}”)
print(f”标准正态分布: {np.random.randn(5)}”)
print(f”1-10之间的随机整数: {np.random.randint(1, 11, 5)}”)
指定分布的随机数¶
print(f”\n正态分布(均值=5, 标准差=2): {np.random.normal(5, 2, 5)}”)
print(f”均匀分布(2-8之间): {np.random.uniform(2, 8, 5)}”)
print(f”泊松分布(λ=3): {np.random.poisson(3, 5)}”)
print(f”指数分布(λ=1.5): {np.random.exponential(1.5, 5)}”)
随机选择和打乱¶
data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(f”\n原始数据: {data}”)
print(f”随机选择3个: {np.random.choice(data, 3, replace=False)}”)
print(f”有放回随机选择5个: {np.random.choice(data, 5, replace=True)}”)
打乱数组¶
sh