Python数据分析生态系统包含了多个强大的库,它们各自承担不同的职责。本文将整合NumPy、Pandas、Matplotlib和Seaborn的核心功能,提供一份完整的数据分析实战指南。

环境配置与最佳实践

Jupyter Notebook优化设置

在Mac上使用Jupyter时,通过以下配置可以显著提升绘图质量。在~/.ipython/profile_default/ipython_kernel_config.py中添加:

c.IPKernelApp.matplotlib = 'inline'
c.InlineBackend.figure_format = 'retina'

绘图样式设置

使用更美观的绘图样式:

import matplotlib.pyplot as plt
plt.style.use('seaborn')

# 查看所有可用样式
print(plt.style.available)

推荐使用的样式包括:'seaborn''ggplot''bmh'等。

核心库导入

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_iris

NumPy:高效数值计算基础

NumPy是Python数据分析的基石,提供了高性能的多维数组和数值计算功能。

数组创建与基本操作

# 加载示例数据
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']

# 选择特定列
data = np.array(df.iloc[:100, [0, 1, -1]])
print(f"DataFrame shape: {df.shape}")  # (150, 5)
print(f"Data shape: {data.shape}")     # (100, 3)

数据提取技巧

从ndarray提取数据和标签:

# 假设最后一列是标签,前面是特征
X = dataset[:, 0:-1]  # 或 dataset[:, 0:8]
y = dataset[:, 8]

从DataFrame提取数据和标签:

X, y = data.iloc[:, :-1], data.iloc[:, -1]

分离特征和标签:

# 获取前两列特征和最后一列标签
X, y = data[:, :-1], data[:, -1]
print(f"X shape: {X.shape}")  # (100, 2)
print(f"y shape: {y.shape}")  # (100,)

数组切片的重要区别

理解切片的维度差异至关重要:

an_array = np.array([[11, 12, 13, 14],
                     [21, 22, 23, 24],
                     [31, 32, 33, 34]])

row_rank1 = an_array[1, :]    # shape: (4,) - 一维数组
row_rank2 = an_array[1:2, :]  # shape: (1, 4) - 二维数组

布尔索引与条件过滤

an_ndarray = np.array([[11, 12], [21, 22], [31, 31]])

# 方法1:显式创建布尔数组
bigger_than_fifteen = (an_ndarray > 15)
filtered = an_ndarray[bigger_than_fifteen]

# 方法2:直接使用条件表达式
filtered = an_ndarray[(an_ndarray > 15)]

标签转换

使用列表推导式进行标签转换:

# 二分类转换
y = np.array([1 if i == 1 else -1 for i in y])

统计运算

# 基本统计
an_ndarray.mean()              # 所有元素均值
an_ndarray.mean(axis=1)        # 每行均值
an_ndarray.mean(axis=0)        # 每列均值
an_ndarray.sum()               # 所有元素和

# 中位数计算
np.median(an_ndarray, axis=1)  # 每行中位数
np.median(an_ndarray, axis=0)  # 每列中位数

# 唯一值
np.unique(an_ndarray)

集合操作

s1 = np.array(['desk', 'chair', 'bulb'])
s2 = np.array(['lamp', 'bulb', 'chair'])

# 交集
np.intersect1d(s1, s2)

# 去重并集
np.union1d(s1, s2)

# 差集(在s1但不在s2)
np.setdiff1d(s1, s2)

# 判断元素是否在s2中
np.in1d(s1, s2)

文件存取

# 二进制格式(推荐)
x = np.array([23.23, 24.24])
np.save('an_array', x)
loaded = np.load('an_array.npy')

# 文本格式
np.savetxt('array.txt', X=x, delimiter=',')
loaded = np.loadtxt('array.txt', delimiter=',')

数组拼接

K = np.random.randint(low=2, high=50, size=(2, 2))
M = np.random.randint(low=2, high=50, size=(2, 2))

# 垂直拼接(行)
np.vstack((K, M))

# 水平拼接(列)
np.hstack((K, M))

# 使用concatenate(更灵活)
np.concatenate([K, M], axis=0)      # 等价于vstack
np.concatenate([K, M.T], axis=1)    # 水平拼接转置后的M

Pandas:数据处理的瑞士军刀

Pandas建立在NumPy之上,提供了更高级的数据结构和数据分析工具。

数据加载与预处理

读取数据时处理空值:

# 读取时指定空值表示
auto = pd.read_csv('Data/Auto.csv', na_values='?').dropna()

# 选择特定列
credit = pd.read_csv('Data/Credit.csv', usecols=list(range(1, 12)))
advertising = pd.read_csv('Data/Advertising.csv', usecols=[1, 2, 3, 4])

# 设置索引列
data = pd.read_csv('../data/Smarket.csv', index_col=0)

使用sklearn数据集:

from sklearn.datasets import load_boston
boston = pd.DataFrame(load_boston().data, columns=load_boston().feature_names)

数据清洗

替换异常值:

auto['horsepower'] = auto['horsepower'].replace('?', np.nan)

删除空值:

auto = auto.dropna()

类型转换:

auto['horsepower'] = auto['horsepower'].astype('int')

原地替换:

df_x.replace(to_replace={0: 'No', 1: 'Yes', 'True': 'Yes', 'False': 'No'},
            inplace=True)

数据选择与过滤

使用iloc选择:

# 选择所有行,从第二列开始的所有列
data = data.iloc[:, 1:]

# 选择特定行列
corr_matrix = boston.corr()
corr_matrix.iloc[1:, 0].sort_values()

条件筛选:

# 筛选特定条件的行
elite_colleges = college[college['Elite'] == 'Yes']

# 根据索引删除行
info = auto.drop(auto.index[10:85]).describe().T

数据排序

# 单列排序
auto = auto.sort_values(by=['horsepower'], ascending=True, axis=0)

# 多列排序
boston.sort_values(by=['CRIM', 'TAX', 'PTRATIO'], ascending=False).head().index

数据转换

条件赋值:

# 使用np.where
college['Elite'] = np.where(college['Top10perc'] > 50, 'Yes', 'No')

# 使用map
credit['Student2'] = credit.Student.map({'No': 0, 'Yes': 1})

分桶操作:

college['Enroll'] = pd.cut(college['Enroll'], bins=3,
                           labels=['Low', 'Medium', 'High'])

创建新列:

info['range'] = info['max'] - info['min']
info = info[['mean', 'range', 'std']]

数据框操作

设置索引:

college = college.set_index(['Unnamed: 0'], append=True, verify_integrity=True)
college.rename_axis([None, 'Name'], inplace=True)

拼接数据框:

# 按列拼接
features = pd.concat([constant, features], axis=1)

构造数据框:

X = np.random.normal(size=100)
y = np.random.permutation(X)
data = pd.DataFrame({'X': X, 'y': y})

数据探索

# 查看唯一值数量
auto.nunique()

# 查看数据类型和内存使用
auto.info()

# 查看某列的唯一值
auto['horsepower'].unique()

# 值计数
college['Elite'].value_counts()

Matplotlib:基础可视化

Matplotlib是Python最基础的可视化库,提供了完整的绘图API。

基础图形

散点图与曲线图:

plt.figure(figsize=(14, 8))
plt.scatter(auto['horsepower'], auto['mpg'])
plt.plot(auto['horsepower'], pred_1, color='orange', label='Degree 1')
plt.plot(auto['horsepower'], pred_2, color='green', label='Degree 2')
plt.plot(auto['horsepower'], pred_5, color='black', label='Degree 5')
plt.show()

直方图:

fig = plt.figure()

plt.subplot(2, 2, 1)
college['Enroll'].value_counts().plot.bar(title='Enroll')

plt.subplot(2, 2, 2)
college['PhD'].value_counts().plot.bar(title='PhD')

plt.subplot(2, 2, 3)
college['Terminal'].value_counts().plot.bar(title='Terminal')

# 调整子图间距
fig.subplots_adjust(hspace=1)

添加参考线:

error_1 = auto['mpg'] - pred_1
plt.figure(figsize=(12, 6))
sns.scatterplot(x=auto['mpg'], y=error_1)
plt.axhline(y=0, linestyle='dashed', color='black', linewidth=0.5)

图表装饰

设置标签和标题:

plt.xlabel('Fitted Values')
plt.ylabel('Residuals')
plt.title('Residual Plot')

添加图例:

plt.figure(figsize=(14, 6))
sns.scatterplot(X, Y)
plt.xlabel('X')
plt.ylabel('Y')

plt.plot(data['X'], lin_model.predict(data['X'].to_frame()),
         color='orange', label='Predicted Line')
plt.plot(tmp_x, tmp_y, color='green', label='True Line')
plt.legend()
plt.show()

坐标轴控制

设置坐标范围:

plt.xlim(-10, 310)
plt.ylim(ymin=0)

等比例坐标轴:

fig, ax = plt.subplots()
sns.scatterplot(simple_coeff, multi_coeff)

lims = [
    np.min([ax.get_xlim(), ax.get_ylim()]),
    np.max([ax.get_xlim(), ax.get_ylim()])
]

ax.plot(lims, lims, 'k-', alpha=0.75, zorder=0, color='orange')
ax.set_aspect('equal')
ax.set_xlim(lims)
ax.set_ylim(lims)

高级绘图

等高线图和3D图:

from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(15, 6))
fig.suptitle('RSS - Regression coefficients', fontsize=20)

ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122, projection='3d')

# 等高线图
CS = ax1.contour(xx, yy, Z, cmap=plt.cm.Set1,
                 levels=[2.15, 2.2, 2.3, 2.5, 3])
ax1.scatter(regr.intercept_, regr.coef_[0], c='r', label=min_RSS)
ax1.clabel(CS, inline=True, fontsize=10, fmt='%1.1f')

# 3D曲面图
ax2.plot_surface(xx, yy, Z, rstride=3, cstride=3, alpha=0.3)
ax2.contour(xx, yy, Z, zdir='z', offset=Z.min(), cmap=plt.cm.Set1,
            alpha=0.4, levels=[2.15, 2.2, 2.3, 2.5, 3])
ax2.scatter3D(regr.intercept_, regr.coef_[0], min_rss, c='r', label=min_RSS)
ax2.set_zlabel('RSS')

# 通用设置
for ax in fig.axes:
    ax.set_xlabel(r'$\beta_0$', fontsize=17)
    ax.set_ylabel(r'$\beta_1$', fontsize=17)
    ax.legend()

3D散点图:

fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(111, projection='3d')

ax.scatter3D(advertising.Radio, advertising.TV, advertising.Sales, c='r')
ax.set_xlabel('Radio')
ax.set_ylabel('TV')
ax.set_zlabel('Sales')

使用注解:

df.plot('Years', 'Hits', kind='scatter', color='orange', figsize=(7, 6))
plt.xlim(0, 25)
plt.ylim(ymin=-5)
plt.xticks([1, 4.5, 24])
plt.yticks([1, 117.5, 238])
plt.vlines(4.5, ymin=-5, ymax=250)
plt.hlines(117.5, xmin=4.5, xmax=25)
plt.annotate('R1', xy=(2, 117.5), fontsize='xx-large')
plt.annotate('R2', xy=(11, 60), fontsize='xx-large')
plt.annotate('R3', xy=(11, 170), fontsize='xx-large')

Seaborn:高级统计可视化

Seaborn建立在Matplotlib之上,提供了更美观的默认样式和高级统计图表。

常用图表类型

成对关系图:

# 选择特定列
sns.pairplot(college.iloc[:, 1:11])

# 使用所有列
sns.pairplot(auto)

箱线图:

sns.boxplot(x=college['Private'], y=college['Outstate'])

回归图:

# 简单线性回归
sns.regplot(data['LSTAT'], data['MEDV'])

# 自定义参数
sns.regplot(advertising.TV, advertising.Sales,
            order=1, ci=None,
            scatter_kws={'color': 'r', 's': 9})
plt.xlim(-10, 310)
plt.ylim(ymin=0)

热力图(相关系数矩阵):

sns.heatmap(auto.iloc[:, :-1].corr())

按类别分组可视化

使用hue参数:

plt.figure(figsize=(12, 8))

tmp = pd.DataFrame({
    'Lag1': X_train['Lag1'],
    'Lag2': X_train['Lag2'],
    'Direction': y_train
})

sns.scatterplot(y='Lag2', x='Lag1', hue='Direction', data=tmp)

复杂多图布局:

import matplotlib.gridspec as gridspec

fig = plt.figure(figsize=(12, 5))
gs = gridspec.GridSpec(1, 4)
ax1 = plt.subplot(gs[0, :-2])
ax2 = plt.subplot(gs[0, -2])
ax3 = plt.subplot(gs[0, -1])

# 采样策略
df_no = df[df.default2 == 0].sample(frac=0.15)
df_yes = df[df.default2 == 1]
df_ = df_no.append(df_yes)

# 散点图
ax1.scatter(df_[df_.default == 'Yes'].balance,
            df_[df_.default == 'Yes'].income,
            s=40, c='orange', marker='+', linewidths=1)
ax1.scatter(df_[df_.default == 'No'].balance,
            df_[df_.default == 'No'].income,
            s=40, marker='o', linewidths=1,
            edgecolors='lightblue', facecolors='white', alpha=.6)

# 箱线图
c_palette = {'No': 'lightblue', 'Yes': 'orange'}
sns.boxplot('default', 'balance', data=df, orient='v',
            ax=ax2, palette=c_palette)
sns.boxplot('default', 'income', data=df, orient='v',
            ax=ax3, palette=c_palette)

gs.tight_layout(plt.gcf())

实战案例:完整数据分析流程

让我们通过一个完整的案例整合所学知识:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_iris

# 1. 数据加载
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['species'] = pd.Categorical.from_codes(iris.target, iris.target_names)

# 2. 数据探索
print(f"数据形状: {df.shape}")
print(f"\n数据类型:\n{df.dtypes}")
print(f"\n基本统计:\n{df.describe()}")

# 3. 数据可视化
plt.style.use('seaborn')

# 成对关系
sns.pairplot(df, hue='species', height=2.5)
plt.suptitle('Iris数据集特征关系', y=1.02)

# 相关性热力图
plt.figure(figsize=(10, 8))
sns.heatmap(df.iloc[:, :4].corr(), annot=True, cmap='coolwarm')
plt.title('特征相关性矩阵')

# 4. 特征工程
df['sepal_area'] = df['sepal length (cm)'] * df['sepal width (cm)']
df['petal_area'] = df['petal length (cm)'] * df['petal width (cm)']

# 5. 数据转换
species_map = {'setosa': 0, 'versicolor': 1, 'virginica': 2}
df['species_code'] = df['species'].map(species_map)

# 6. 高级分析
# 按物种分组统计
group_stats = df.groupby('species').agg({
    'sepal length (cm)': ['mean', 'std'],
    'petal length (cm)': ['mean', 'std']
})

print("\n按物种分组的统计信息:")
print(group_stats)

# 7. 可视化结果
fig, axes = plt.subplots(2, 2, figsize=(12, 10))

df.boxplot(column='sepal length (cm)', by='species', ax=axes[0, 0])
df.boxplot(column='petal length (cm)', by='species', ax=axes[0, 1])

for species, color in zip(['setosa', 'versicolor', 'virginica'], ['red', 'green', 'blue']):
    subset = df[df['species'] == species]
    axes[1, 0].scatter(subset['sepal length (cm)'],
                       subset['petal length (cm)'],
                       label=species, alpha=0.6)

axes[1, 0].set_xlabel('Sepal Length')
axes[1, 0].set_ylabel('Petal Length')
axes[1, 0].legend()
axes[1, 0].set_title('萼片vs花瓣长度')

plt.tight_layout()
plt.show()

最佳实践与技巧

性能优化

  1. 使用向量化操作:避免在DataFrame上使用循环
  2. 合理使用数据类型category类型用于低基数分类变量
  3. 批量操作:使用apply()而不是逐行迭代

代码可读性

  1. 方法链df.dropna().sort_values().groupby()
  2. 有意义的变量名df_filtered而不是df2
  3. 注释和文档:解释复杂的数据转换逻辑

调试技巧

# 检查缺失值
df.isnull().sum()

# 检查数据类型
df.dtypes

# 查看内存使用
df.memory_usage()

# 采样查看大数据集
df.sample(100)

常见问题与解决方案

axis参数的理解

  • axis=0:沿列向下操作(行操作)
  • axis=1:沿行向右操作(列操作)
df.mean(axis=0)  # 每列的均值
df.mean(axis=1)  # 每行的均值

copy与view的区别

# 创建副本(推荐)
df_copy = df.copy()

# 可能创建视图
df_view = df.iloc[:, :2]

# 修改视图可能影响原数据
df_view.iloc[0, 0] = 999  # 可能影响df

链式赋值警告

# 避免
df[df['A'] > 0]['B'] = 1  # 警告

# 推荐
df.loc[df['A'] > 0, 'B'] = 1

总结

Python数据分析工具链的掌握需要理解各库的职责分工:

  • NumPy:底层数值计算,高性能数组操作
  • Pandas:数据清洗、转换、分析的核心工具
  • Matplotlib:灵活的基础绘图库
  • Seaborn:美观的统计可视化

通过本文的整合学习,你应该能够:

  1. 使用NumPy进行高效的数值计算
  2. 使用Pandas进行数据清洗和转换
  3. 使用Matplotlib和Seaborn创建各种可视化图表
  4. 理解完整的数据分析工作流程

持续练习和实际项目应用是掌握这些工具的关键。建议使用真实的 Kaggle 数据集或工作中的实际问题来巩固所学知识。

参考资源