第12章:Python 数据分析
12.1 数据分析概述
数据分析是指通过收集、处理、分析数据,提取有价值的信息和洞察的过程。Python 凭借其丰富的库生态系统,成为数据分析的热门工具。
数据分析的基本步骤
- 数据收集:获取原始数据
- 数据清洗:处理缺失值、异常值等
- 数据探索:了解数据的基本特征
- 数据预处理:转换数据格式、特征工程等
- 数据分析:使用统计方法、机器学习算法等
- 数据可视化:展示分析结果
- 结果解释:得出结论并提出建议
常用的数据分析库
| 库 | 描述 | 用途 |
|---|---|---|
| NumPy | 数值计算库 | 数组操作、数学运算 |
| Pandas | 数据处理库 | 数据清洗、转换、分析 |
| Matplotlib | 数据可视化库 | 绘制图表 |
| Seaborn | 统计数据可视化库 | 高级图表、统计图形 |
| Scikit-learn | 机器学习库 | 机器学习算法 |
| SciPy | 科学计算库 | 统计分析、优化等 |
12.2 NumPy 库
NumPy(Numerical Python)是 Python 中用于科学计算的核心库,提供了高效的多维数组操作。
安装 NumPy
pip install numpy
NumPy 数组
import numpy as np
# 创建一维数组
arr1 = np.array([1, 2, 3, 4, 5])
print(arr1)
print(type(arr1))
print(arr1.shape)
# 创建二维数组
arr2 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr2)
print(arr2.shape)
# 创建特殊数组
zeros = np.zeros((2, 3)) # 全零数组
print(zeros)
ones = np.ones((2, 3)) # 全一数组
print(ones)
full = np.full((2, 3), 5) # 填充指定值
print(full)
identity = np.eye(3) # 单位矩阵
print(identity)
range_arr = np.arange(0, 10, 2) # 范围数组
print(range_arr)
linspace = np.linspace(0, 10, 5) # 等间隔数组
print(linspace)
# 随机数组
random = np.random.random((2, 3)) # 0-1 随机数
print(random)
randint = np.random.randint(0, 10, (2, 3)) # 随机整数
print(randint)
数组操作
import numpy as np
# 数组索引和切片
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr[0, 0]) # 单个元素
print(arr[0, :]) # 第一行
print(arr[:, 0]) # 第一列
print(arr[0:2, 0:2]) # 子数组
# 数组运算
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
print(arr1 + arr2) # 加法
print(arr1 - arr2) # 减法
print(arr1 * arr2) # 乘法(元素级)
print(arr1 / arr2) # 除法
print(arr1 ** 2) # 平方
# 广播
arr3 = np.array([[1, 2, 3], [4, 5, 6]])
scalar = 2
print(arr3 * scalar) # 广播标量
# 聚合函数
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(np.sum(arr)) # 总和
print(np.mean(arr)) # 平均值
print(np.min(arr)) # 最小值
print(np.max(arr)) # 最大值
print(np.std(arr)) # 标准差
print(np.argmax(arr)) # 最大值索引
# 轴操作
print(np.sum(arr, axis=0)) # 按列求和
print(np.sum(arr, axis=1)) # 按行求和
# 数组形状操作
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.shape) # (2, 3)
# 重塑
reshaped = arr.reshape(3, 2)
print(reshaped)
# 扁平化
flattened = arr.flatten()
print(flattened)
# 转置
transposed = arr.T
print(transposed)
线性代数
import numpy as np
# 矩阵乘法
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print(np.dot(A, B)) # 矩阵乘法
print(A @ B) # 矩阵乘法(Python 3.5+)
# 逆矩阵
inv_A = np.linalg.inv(A)
print(inv_A)
# 行列式
det_A = np.linalg.det(A)
print(det_A)
# 特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eig(A)
print(eigenvalues)
print(eigenvectors)
# 求解线性方程组
# Ax = b
A = np.array([[2, 3], [1, -2]])
b = np.array([8, -3])
x = np.linalg.solve(A, b)
print(x)
12.3 Pandas 库
Pandas 是 Python 中用于数据处理和分析的强大库,提供了 DataFrame 和 Series 两种主要数据结构。
安装 Pandas
pip install pandas
Series
Series 是一维标签数组,类似于带标签的 NumPy 数组。
import pandas as pd
# 创建 Series
s1 = pd.Series([1, 2, 3, 4, 5])
print(s1)
# 带索引的 Series
s2 = pd.Series([1, 2, 3, 4, 5], index=['a', 'b', 'c', 'd', 'e'])
print(s2)
# 从字典创建 Series
data = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
s3 = pd.Series(data)
print(s3)
# 访问元素
print(s2['a'])
print(s2[0])
print(s2[['a', 'c', 'e']])
# 布尔索引
print(s2[s2 > 3])
# 基本运算
print(s2 + 1)
print(s2 * 2)
print(s2.mean())
print(s2.sum())
print(s2.max())
print(s2.min())
DataFrame
DataFrame 是二维标签数据结构,类似于表格。
import pandas as pd
# 创建 DataFrame
data = {
'name': ['John', 'Alice', 'Bob', 'Charlie', 'David'],
'age': [30, 25, 35, 40, 28],
'city': ['New York', 'London', 'Paris', 'Tokyo', 'Sydney'],
'salary': [50000, 60000, 70000, 80000, 55000]
}
df = pd.DataFrame(data)
print(df)
# 查看数据
print(df.head()) # 前 5 行
print(df.tail()) # 后 5 行
print(df.info()) # 数据信息
print(df.describe()) # 统计信息
# 访问列
print(df['name'])
print(df[['name', 'age']])
# 访问行
print(df.loc[0]) # 按标签访问
print(df.iloc[0]) # 按位置访问
print(df.loc[0:2, ['name', 'age']]) # 切片
# 布尔索引
print(df[df['age'] > 30])
print(df[(df['age'] > 30) & (df['salary'] > 60000)])
# 添加列
df['bonus'] = df['salary'] * 0.1
print(df)
# 修改列
df['salary'] = df['salary'] + 1000
print(df)
# 删除列
df = df.drop('bonus', axis=1)
print(df)
# 排序
df_sorted = df.sort_values('age', ascending=False)
print(df_sorted)
# 分组
grouped = df.groupby('city')
print(grouped.mean())
print(grouped.sum())
数据读取和写入
import pandas as pd
# 读取 CSV 文件
df = pd.read_csv('data.csv')
print(df)
# 写入 CSV 文件
df.to_csv('output.csv', index=False)
# 读取 Excel 文件
df = pd.read_excel('data.xlsx')
print(df)
# 写入 Excel 文件
df.to_excel('output.xlsx', index=False)
# 读取 JSON 文件
df = pd.read_json('data.json')
print(df)
# 写入 JSON 文件
df.to_json('output.json')
# 读取 SQL 数据库
import sqlite3
conn = sqlite3.connect('example.db')
df = pd.read_sql('SELECT * FROM users', conn)
print(df)
# 写入 SQL 数据库
df.to_sql('users', conn, if_exists='replace', index=False)
数据清洗
import pandas as pd
import numpy as np
# 创建含有缺失值的数据
data = {
'name': ['John', 'Alice', 'Bob', 'Charlie', 'David'],
'age': [30, np.nan, 35, 40, 28],
'city': ['New York', 'London', np.nan, 'Tokyo', 'Sydney'],
'salary': [50000, 60000, 70000, np.nan, 55000]
}
df = pd.DataFrame(data)
print(df)
# 检查缺失值
print(df.isnull())
print(df.isnull().sum())
# 处理缺失值
# 删除含有缺失值的行
df_dropna = df.dropna()
print(df_dropna)
# 填充缺失值
df_fillna = df.fillna({
'age': df['age'].mean(),
'city': 'Unknown',
'salary': df['salary'].median()
})
print(df_fillna)
# 处理重复值
df_duplicates = pd.DataFrame([
['John', 30, 'New York', 50000],
['John', 30, 'New York', 50000],
['Alice', 25, 'London', 60000]
], columns=['name', 'age', 'city', 'salary'])
print(df_duplicates)
# 检查重复值
print(df_duplicates.duplicated())
# 删除重复值
df_unique = df_duplicates.drop_duplicates()
print(df_unique)
# 数据类型转换
df['age'] = df['age'].astype('int64', errors='ignore')
print(df.dtypes)
# 字符串处理
df['city'] = df['city'].str.upper()
print(df)
# 日期处理
df['date'] = pd.date_range('2023-01-01', periods=5)
print(df)
print(df['date'].dt.year)
print(df['date'].dt.month)
print(df['date'].dt.day)
12.4 Matplotlib 库
Matplotlib 是 Python 中用于数据可视化的库,提供了各种图表类型。
安装 Matplotlib
pip install matplotlib
基本图表
import matplotlib.pyplot as plt
import numpy as np
# 折线图
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.figure(figsize=(10, 6))
plt.plot(x, y, label='sin(x)')
plt.title('Sin Wave')
plt.xlabel('X')
plt.ylabel('Y')
plt.grid(True)
plt.legend()
plt.savefig('sin_wave.png')
plt.show()
# 散点图
x = np.random.randn(100)
y = np.random.randn(100)
plt.figure(figsize=(10, 6))
plt.scatter(x, y, c='red', alpha=0.5)
plt.title('Scatter Plot')
plt.xlabel('X')
plt.ylabel('Y')
plt.grid(True)
plt.savefig('scatter_plot.png')
plt.show()
# 柱状图
categories = ['A', 'B', 'C', 'D', 'E']
values = [10, 20, 15, 25, 30]
plt.figure(figsize=(10, 6))
plt.bar(categories, values, color='blue')
plt.title('Bar Chart')
plt.xlabel('Category')
plt.ylabel('Value')
plt.grid(axis='y')
plt.savefig('bar_chart.png')
plt.show()
# 直方图
data = np.random.randn(1000)
plt.figure(figsize=(10, 6))
plt.hist(data, bins=30, alpha=0.7, color='green')
plt.title('Histogram')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.grid(axis='y')
plt.savefig('histogram.png')
plt.show()
# 饼图
labels = ['A', 'B', 'C', 'D']
sizes = [15, 30, 45, 10]
colors = ['gold', 'yellowgreen', 'lightcoral', 'lightskyblue']
plt.figure(figsize=(8, 8))
plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%', startangle=90)
plt.title('Pie Chart')
plt.axis('equal') # 确保饼图是圆形
plt.savefig('pie_chart.png')
plt.show()
子图
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.tan(x)
y4 = np.exp(x)
# 创建 2x2 子图
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 第一个子图
axes[0, 0].plot(x, y1)
axes[0, 0].set_title('Sin Wave')
axes[0, 0].set_xlabel('X')
axes[0, 0].set_ylabel('Y')
axes[0, 0].grid(True)
# 第二个子图
axes[0, 1].plot(x, y2)
axes[0, 1].set_title('Cos Wave')
axes[0, 1].set_xlabel('X')
axes[0, 1].set_ylabel('Y')
axes[0, 1].grid(True)
# 第三个子图
axes[1, 0].plot(x, y3)
axes[1, 0].set_title('Tan Wave')
axes[1, 0].set_xlabel('X')
axes[1, 0].set_ylabel('Y')
axes[1, 0].grid(True)
# 第四个子图
axes[1, 1].plot(x, y4)
axes[1, 1].set_title('Exponential Function')
axes[1, 1].set_xlabel('X')
axes[1, 1].set_ylabel('Y')
axes[1, 1].grid(True)
plt.tight_layout() # 调整布局
plt.savefig('subplots.png')
plt.show()
高级图表
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 热力图
data = np.random.rand(10, 10)
plt.figure(figsize=(10, 8))
heatmap = plt.imshow(data, cmap='viridis')
plt.colorbar(heatmap)
plt.title('Heatmap')
plt.savefig('heatmap.png')
plt.show()
# 箱线图
data = [np.random.randn(100) for _ in range(4)]
plt.figure(figsize=(10, 6))
plt.boxplot(data, labels=['A', 'B', 'C', 'D'])
plt.title('Box Plot')
plt.xlabel('Category')
plt.ylabel('Value')
plt.grid(True)
plt.savefig('box_plot.png')
plt.show()
# 面积图
dates = pd.date_range('2023-01-01', periods=30)
data = pd.DataFrame({
'A': np.random.randn(30).cumsum(),
'B': np.random.randn(30).cumsum(),
'C': np.random.randn(30).cumsum()
}, index=dates)
plt.figure(figsize=(12, 6))
plt.stackplot(data.index, data['A'], data['B'], data['C'], labels=['A', 'B', 'C'])
plt.title('Area Plot')
plt.xlabel('Date')
plt.ylabel('Value')
plt.legend(loc='upper left')
plt.grid(True)
plt.savefig('area_plot.png')
plt.show()
12.5 Seaborn 库
Seaborn 是基于 Matplotlib 的统计数据可视化库,提供了更高级的图表类型。
安装 Seaborn
pip install seaborn
常用图表
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 设置风格
sns.set(style="whitegrid")
# 加载示例数据
tips = sns.load_dataset("tips")
iris = sns.load_dataset("iris")
# 散点图(带回归线)
plt.figure(figsize=(10, 6))
sns.regplot(x="total_bill", y="tip", data=tips)
plt.title('Scatter Plot with Regression Line')
plt.savefig('regplot.png')
plt.show()
# 分类散点图
plt.figure(figsize=(10, 6))
sns.swarmplot(x="day", y="total_bill", data=tips)
plt.title('Swarm Plot')
plt.savefig('swarmplot.png')
plt.show()
# 箱线图
plt.figure(figsize=(10, 6))
sns.boxplot(x="day", y="total_bill", data=tips)
plt.title('Box Plot')
plt.savefig('boxplot.png')
plt.show()
# 小提琴图
plt.figure(figsize=(10, 6))
sns.violinplot(x="day", y="total_bill", data=tips)
plt.title('Violin Plot')
plt.savefig('violinplot.png')
plt.show()
# 热力图(相关性矩阵)
corr = iris.corr()
plt.figure(figsize=(10, 8))
sns.heatmap(corr, annot=True, cmap='coolwarm')
plt.title('Correlation Heatmap')
plt.savefig('heatmap_seaborn.png')
plt.show()
# 配对图
plt.figure(figsize=(12, 10))
sns.pairplot(iris, hue="species")
plt.title('Pair Plot')
plt.savefig('pairplot.png')
plt.show()
# 联合分布图
plt.figure(figsize=(10, 6))
sns.jointplot(x="total_bill", y="tip", data=tips)
plt.savefig('jointplot.png')
plt.show()
12.6 综合示例
示例1:销售数据分析
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# 生成示例数据
dates = pd.date_range('2023-01-01', periods=365)
sales = pd.DataFrame({
'date': dates,
'sales': np.random.randn(365).cumsum() + 100,
'category': np.random.choice(['A', 'B', 'C', 'D'], 365)
})
# 数据探索
print(sales.head())
print(sales.info())
print(sales.describe())
# 按类别分组
category_sales = sales.groupby('category')['sales'].sum()
print(category_sales)
# 时间序列分析
plt.figure(figsize=(12, 6))
sns.lineplot(x='date', y='sales', data=sales)
plt.title('Sales Trend')
plt.xlabel('Date')
plt.ylabel('Sales')
plt.grid(True)
plt.savefig('sales_trend.png')
plt.show()
# 类别销售分析
plt.figure(figsize=(10, 6))
sns.barplot(x=category_sales.index, y=category_sales.values)
plt.title('Sales by Category')
plt.xlabel('Category')
plt.ylabel('Total Sales')
plt.grid(axis='y')
plt.savefig('sales_by_category.png')
plt.show()
# 月度销售分析
sales['month'] = sales['date'].dt.month
monthly_sales = sales.groupby('month')['sales'].mean()
plt.figure(figsize=(12, 6))
sns.barplot(x=monthly_sales.index, y=monthly_sales.values)
plt.title('Monthly Average Sales')
plt.xlabel('Month')
plt.ylabel('Average Sales')
plt.grid(axis='y')
plt.savefig('monthly_sales.png')
plt.show()
示例2: iris 数据集分析
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_iris
# 加载数据
iris = load_iris()
df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
df['species'] = iris.target
df['species_name'] = df['species'].map({0: 'setosa', 1: 'versicolor', 2: 'virginica'})
# 数据探索
print(df.head())
print(df.info())
print(df.describe())
# 相关性分析
corr = df.corr()
plt.figure(figsize=(10, 8))
sns.heatmap(corr, annot=True, cmap='coolwarm')
plt.title('Correlation Heatmap')
plt.savefig('iris_correlation.png')
plt.show()
# 配对图
plt.figure(figsize=(12, 10))
sns.pairplot(df, hue='species_name')
plt.title('Pair Plot')
plt.savefig('iris_pairplot.png')
plt.show()
# 箱线图
plt.figure(figsize=(12, 6))
sns.boxplot(data=df.drop(['species', 'species_name'], axis=1))
plt.title('Box Plot of Features')
plt.savefig('iris_boxplot.png')
plt.show()
# 小提琴图
plt.figure(figsize=(12, 6))
sns.violinplot(x='species_name', y='sepal length (cm)', data=df)
plt.title('Sepal Length by Species')
plt.savefig('iris_violinplot.png')
plt.show()
示例3:房价预测数据探索
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# 加载数据(使用波士顿房价数据集)
from sklearn.datasets import load_boston
boston = load_boston()
df = pd.DataFrame(data=boston.data, columns=boston.feature_names)
df['PRICE'] = boston.target
# 数据探索
print(df.head())
print(df.info())
print(df.describe())
# 相关性分析
corr = df.corr()
plt.figure(figsize=(12, 10))
sns.heatmap(corr, annot=True, cmap='coolwarm')
plt.title('Correlation Heatmap')
plt.savefig('boston_correlation.png')
plt.show()
# 房价分布
plt.figure(figsize=(10, 6))
sns.histplot(df['PRICE'], bins=30)
plt.title('Price Distribution')
plt.xlabel('Price')
plt.ylabel('Frequency')
plt.savefig('price_distribution.png')
plt.show()
# 特征与房价的关系
plt.figure(figsize=(12, 6))
sns.scatterplot(x='RM', y='PRICE', data=df)
plt.title('Price vs. Number of Rooms')
plt.xlabel('Number of Rooms')
plt.ylabel('Price')
plt.savefig('price_vs_rooms.png')
plt.show()
plt.figure(figsize=(12, 6))
sns.scatterplot(x='LSTAT', y='PRICE', data=df)
plt.title('Price vs. Lower Status Population')
plt.xlabel('Lower Status Population (%)')
plt.ylabel('Price')
plt.savefig('price_vs_lstat.png')
plt.show()
12.7 常见问题和解决方案
问题1:数据导入错误
# 错误示例
import pandas as pd
df = pd.read_csv('data.csv') # 文件不存在或格式错误
# 解决方案
import pandas as pd
try:
df = pd.read_csv('data.csv')
print("Data loaded successfully")
except FileNotFoundError:
print("File not found")
except pd.errors.EmptyDataError:
print("File is empty")
except pd.errors.ParserError:
print("File format error")
except Exception as e:
print(f"Error: {e}")
问题2:内存不足
# 解决方案:分块读取大文件
import pandas as pd
# 分块读取
chunks = []
for chunk in pd.read_csv('large_file.csv', chunksize=10000):
# 处理每个块
chunks.append(chunk)
# 合并所有块
df = pd.concat(chunks)
# 或者使用 dask 处理更大的文件
# pip install dask
import dask.dataframe as dd
df = dd.read_csv('very_large_file.csv')
result = df.groupby('column').mean().compute()
问题3:图表显示问题
# 解决方案
import matplotlib.pyplot as plt
# 确保图表显示
plt.figure()
plt.plot([1, 2, 3], [4, 5, 6])
plt.title('Test Plot')
plt.savefig('test_plot.png') # 保存图表
plt.show() # 显示图表
# 在 Jupyter Notebook 中
# %matplotlib inline
问题4:中文显示问题
# 解决方案
import matplotlib.pyplot as plt
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
plt.figure()
plt.plot([1, 2, 3], [4, 5, 6])
plt.title('测试图表') # 中文标题
plt.xlabel('X轴') # 中文标签
plt.ylabel('Y轴') # 中文标签
plt.show()
12.8 练习
- NumPy 练习:创建 NumPy 数组,进行各种数学运算
- Pandas 练习:读取 CSV 文件,进行数据清洗和分析
- Matplotlib 练习:创建各种类型的图表
- Seaborn 练习:使用 Seaborn 创建统计图表
- 综合练习:分析一个真实的数据集,包括数据清洗、探索、可视化
- 挑战练习:使用机器学习算法对数据进行预测分析
12.9 小结
本章我们学习了:
- 数据分析的基本概念和步骤
- NumPy 库的使用(数组操作、数学运算)
- Pandas 库的使用(DataFrame、数据处理、数据清洗)
- Matplotlib 库的使用(各种图表类型)
- Seaborn 库的使用(统计数据可视化)
- 综合示例
现在你已经掌握了 Python 的数据分析技能,可以开始应用这些知识来解决实际问题了!
12.10 进一步学习资源
-
官方文档:
- NumPy: https://numpy.org/doc/
- Pandas: https://pandas.pydata.org/docs/
- Matplotlib: https://matplotlib.org/stable/contents.html
- Seaborn: https://seaborn.pydata.org/
-
在线课程:
- Coursera: Python for Data Science and Machine Learning Bootcamp
- edX: Data Science Essentials
- Udemy: Python for Data Analysis
-
书籍:
- 《Python for Data Analysis》 by Wes McKinney
- 《NumPy Beginner's Guide》 by Ivan Idris
- 《Matplotlib for Python Developers》 by Sandro Tosi
-
实践项目:
- Kaggle: https://www.kaggle.com/
- UCI Machine Learning Repository: https://archive.ics.uci.edu/ml/index.php
通过不断练习和实践,你将能够熟练掌握 Python 数据分析技能,为解决实际问题提供有力支持。