由于直接提供截图是不切实际的,我将详细解释如何使用scikit-learn
(通常称为sk-learn
)自带的红酒数据集进行葡萄酒数据的分析与处理。这包括实验要求的分析、数据的初步分析(完整性和重复性)以及特征之间的关联关系分析。
1. 分析实验要求
实验的主要目标是使用scikit-learn
中的红酒数据集(通常是UCI机器学习库中的Wine Recognition dataset)来分析葡萄酒的化学成分与葡萄酒类型或质量之间的关系。通常,该数据集包含多种葡萄酒的化学成分(如酒精度、苹果酸含量等)以及葡萄酒的类别或质量评分。
2. 初步分析数据
2.1 加载数据
首先,你需要加载红酒数据集。在scikit-learn
中,这可以通过load_wine
函数完成。
# 导入必要的库
from sklearn.datasets import load_wine
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# 加载红酒数据集
wine_data = load_wine()
# 将数据转换为Pandas DataFrame
df = pd.DataFrame(wine_data.data, columns=wine_data.feature_names)
df['class'] = wine_data.target # 将目标变量(葡萄酒的类别)添加到DataFrame中
2.2 检查数据的完整性和重复性
- 完整性:通过检查数据的形状(shape)和特征名称(feature_names)来验证数据是否完整。
# 检查数据的形状
print("Data shape:", df.shape) # 查看样本数量和特征数量
- 重复性:在大多数情况下,UCI数据集不会包含重复的样本。然而,为了确认,你可以使用Pandas库检查数据的唯一性。
# 检查是否有重复的行
print("Number of duplicate rows:", df.duplicated().sum()) # 如果输出为0,则表示没有重复行
3. 分析实验数据各特征之间的关联关系
3.1 使用统计方法
使用Pandas的describe
函数查看特征的统计描述,包括均值、标准差等,这些可以帮助你了解数据的分布情况。
print(df.describe())
3.2 绘制直方图和箱线图
绘制特征的直方图和箱线图,以观察特征的分布和可能的异常值。
# 绘制直方图
df.iloc[:, :-1].hist(bins=30, figsize=(15, 10), layout=(4, 4))
plt.tight_layout()
plt.show()
# 使用subplots=True让matplotlib自动处理布局
# df.iloc[:, :-1].hist(bins=30, figsize=(15, 15), layout=None, subplots=True)
# plt.tight_layout() # 尝试调整子图参数, 以便子图之间的重叠最小化
# plt.show()
# 绘制箱线图
plt.figure(figsize=(10, 8))
sns.boxplot(data=df.iloc[:, :-1])
plt.title('Boxplot of Wine Dataset Features')
plt.show()
subplots是一个用来控制自动处理布局的参数,但在这里是不适用的,因为hist
方法在 pandas 的 DataFrame
中并没有 subplots
参数。 subplots=True
是不适用于 pandas 的 hist
方法的,这是 matplotlib 中某些函数(如 subplot_mosaic
或在创建多个子图时)的参数。
为了在 pandas 中绘制多个特征的直方图,并且让 pandas 自动处理子图的布局,应该使用 subplots=True
的方式,但这不是通过 hist
方法的参数来实现的。相反,你需要调整 figsize
来确保图形足够大,以容纳所有特征的直方图。由于 pandas 的 hist
方法不直接支持复杂的子图布局,它通常会将所有直方图绘制在一个连续的网格中,或者可以通过迭代每列来手动创建子图。
为了简化这个过程,我们可以使用 pandas 的 hist
方法,并接受它自动选择的布局,或者我们可以使用 matplotlib 的子图功能来更精细地控制布局。
以下是使用 pandas hist
方法并调整 figsize
的示例:
(figsize:指定figure的宽和高,单位为英寸)
# 绘制特征分布的直方图
fig, axes = plt.subplots(nrows=4, ncols=4, figsize=(15, 15)) # 假设4x4布局,但会有些空白
axes = axes.flatten() # 将二维数组转换为一维,以便迭代
# 注意:如果特征数量不是16个,则以下循环将不会为所有特征绘制直方图
# 或者,你可以根据特征数量动态调整nrows和ncols
for i, feature in enumerate(df.columns[:-1]): # 遍历除'class'之外的所有特征
if i < len(axes): # 确保索引不会超出axes的长度
df[feature].hist(ax=axes[i], bins=30)
axes[i].set_title(feature)
else:
# 如果特征数量超过16个,你可以在这里添加代码来处理额外的特征
# 例如,创建一个新的图形或调整布局
break
# 如果特征数量少于16个,可以移除多余的子图(可选)
for ax in axes[len(df.columns[:-1]):]:
ax.remove()
plt.tight_layout()
plt.show()
上面的代码在特征数量不是16个时会留下空白的子图。一个更灵活的方法是使用 GridSpec
或类似的方法来动态地创建子图网格。不过,对于简单的用例,可能只需要调整 figsize
并接受 pandas hist
方法的默认布局。
如果只是想让 pandas 自动处理布局,并希望图形足够大以清晰显示所有直方图,可以这样做:
# 绘制特征分布的直方图,让pandas自动处理布局
df.iloc[:, :-1].hist(bins=30, figsize=(15, 20)) # 调整figsize的高度以容纳更多直方图
plt.tight_layout() # 尝试调整子图参数,但效果可能有限
plt.show()
3.3 计算特征之间的相关性
使用Pandas的corr
函数计算特征之间的相关系数(如皮尔逊相关系数),以分析它们之间的线性关系。
# 计算特征之间的相关系数矩阵
correlation_matrix = df.iloc[:, :-1].corr() # 排除'class'列
# 打印相关系数矩阵
print("Correlation Matrix:")
print(correlation_matrix)
# 绘制热力图以更直观地查看相关性
plt.figure(figsize=(10, 8))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm')
plt.title('Correlation Heatmap of Wine Dataset Features')
plt.show()
注意:
pandas
用于数据处理,matplotlib.pyplot
和seaborn
用于数据可视化。- 使用
load_wine
函数加载了红酒数据集,并将其转换为pandas.DataFrame
以便于处理。 - 在分析特征之间的关联关系时,排除了目标变量
'class'
列,只计算了特征之间的相关系数。 - 绘制直方图和箱线图时,
layout
参数要根据特征数目进行相应的调整。如果特征数量不是3的倍数,可能需要调整layout
参数或使用plt.subplots
来更灵活地控制子图的布局。 seaborn
的heatmap
函数用于绘制相关系数矩阵的热力图,它提供了直观的视觉表示来查看哪些特征之间存在强相关性
结果:
4.决策树模型:
(使用准确度和AUC指标进行模型评估)
准确度指标:
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 训练模型
clf = DecisionTreeClassifier(random_state=42)
clf.fit(X_train, y_train)
# 预测测试集
y_pred = clf.predict(X_test)
# 评估模型(准确度)
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2f}")
AUC指标:
y_scores = clf.predict_proba(X_test) # 获取每个类别的概率
auc = roc_auc_score(y_test, y_scores, multi_class='ovr', average='macro')
print(f"Macro-average AUC: {auc:.2f}")
clf
:这是一个已经训练好的分类器对象,在这个例子中,它是一个DecisionTreeClassifier
实例。.predict_proba(X_test)
:这是clf
对象的一个方法,用于对给定的测试集X_test
中的样本进行预测,但它不直接给出类标签(即预测结果所属的类别),而是给出每个样本属于各个类别的概率。这个方法返回一个二维数组,其中每一行对应X_test
中的一个样本,每一列对应一个类别,元素值是该样本属于对应类别的概率。y_scores
:这个变量接收了.predict_proba(X_test)
方法的返回值,即测试集中每个样本属于各个类别的概率。
第二行代码用于计算ROC曲线下的面积(AUC):
y_test
:这是测试集的真实标签,即每个样本的实际类别。y_scores
:这是通过.predict_proba(X_test)
得到的预测概率。multi_class='ovr'
:这个参数指定了如何将多分类问题转换为多个二分类问题以计算AUC。'ovr'
代表“一对一”(One-vs-Rest),即对于每个类别,都将其视为正类,其余所有类别视为负类,然后计算每个类别的ROC AUC,最后通过某种方式(如平均)汇总这些AUC值。average='macro'
:这个参数指定了如何汇总每个类别的AUC值。'macro'
意味着简单地计算所有类别AUC的未加权平均值。
AUC(Area Under the Curve)通常用于评估二分类问题的ROC曲线下的面积,但葡萄酒数据集是一个多分类问题。对于多分类问题,我们可以计算加权平均AUC(通过roc_auc_score
的multi_class
参数设置为ovr
或ovo
),但更常见的做法是使用准确度、F1分数、混淆矩阵等指标。
如果数据集是高度不平衡的,使用精确度-召回率曲线可能更加合适,因为它能更好地反映模型在少数类上的性能 。
结果:
5.随机森林:
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 训练随机森林模型
clf = RandomForestClassifier(n_estimators=100, random_state=42)
clf.fit(X_train, y_train) # 注意:ravel()将y_train从二维数组转换为一维数组
#预测测试集的概率
y_score = clf.predict_proba(X_test)
# 评估模型(准确度)
# 预测测试集的标签
y_pred = clf.predict(X_test) # 注意:这里使用原始标签的索引进行预测
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2f}")
auc = roc_auc_score(y_test, y_score, multi_class='ovr', average='macro')
print(f"Macro-average AUC: {auc:.2f}")
结果:
(居然准确度和AUC指标都是1!!怀疑)
如果你得到的准确度和AUC都为1,这通常意味着你的模型在测试集上表现得非常完美,几乎没有任何错误。然而,这种情况在实际应用中是非常罕见的,特别是当使用随机森林这样的集成学习方法时,因为数据集通常包含一些噪声或难以预测的样本。
不放心搜了一下出现这种情况的原因,大家可以参考一下:
以下是一些可能导致这种情况的原因:
-
过拟合:模型在训练集上表现得太好,以至于它学习到了训练数据中的噪声或特定模式,而这些模式在测试集中并不适用。然而,随机森林通常具有较好的抗过拟合能力,所以这可能是不太可能的原因,除非数据集非常小或非常特殊。
-
数据泄漏:在训练和测试集之间存在某种形式的重叠或信息泄漏。例如,如果测试集中的某些样本在无意中用于训练模型,或者如果特征和标签之间存在直接的依赖关系(这些依赖关系在训练集和测试集中都被保留了下来),那么模型可能会表现得异常好。
-
简单的数据集:数据集可能非常简单,以至于即使是随机猜测也能得到很好的结果。然而,由于你正在使用随机森林这样的复杂模型,并且通常预期它在更复杂的数据集上也能表现良好,所以这种情况也不太可能。
-
标签不平衡:如果测试集中的大多数样本都属于同一个类别,并且模型只是简单地预测这个最常见的类别,那么准确度可能会很高,但这并不意味着模型实际上能够区分不同的类别。然而,在这种情况下,AUC通常不会接近1,因为它考虑了所有类别的区分能力。
-
随机性:虽然你设置了
random_state
来确保结果的可重复性,但随机森林的每次运行都可能略有不同(尽管差异很小)。然而,这种随机性不太可能导致准确度和AUC都为1。 -
评估错误:可能你在评估模型时犯了某种错误。例如,你可能错误地将训练集用作测试集,或者你可能在计算AUC时使用了错误的参数或方法。
-
模型参数:在某些情况下,随机森林的参数(如
n_estimators
)可能被设置得非常高,导致模型过度拟合训练数据。然而,即使在这种情况下,通常也不会看到准确度和AUC都为1的完美结果。
为了诊断这个问题,可以尝试以下步骤:
- 检查数据:确保训练集和测试集之间没有重叠,并且它们都正确地反映了你要解决的问题。
- 检查标签:确保测试集的标签是正确的,并且没有误用训练集的标签。
- 交叉验证:使用交叉验证来评估模型,这可以帮助你了解模型在不同测试集上的表现。
- 简化模型:尝试使用更简单的模型(如决策树)来查看是否仍然得到相同的结果。
- 检查AUC计算:确保你正确地计算了AUC,并且使用了适当的参数(如
multi_class='ovr'
和average='macro'
)。如果你对二分类问题使用AUC,请确保你的问题是二分类的,或者你已经将多类问题转换为了多个二分类问题。 - 查看预测结果:查看模型的预测结果,特别是那些被错误分类的样本,以了解模型可能存在的问题。
- 调整模型参数:尝试调整随机森林的参数,如
n_estimators
、max_depth
等,以查看是否对结果有影响。然而,请注意,过度调整参数可能会导致过拟合。
6.调试
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test);
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [None, 10, 20, 30],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4]
}
grid_search = GridSearchCV(clf, param_grid, cv=5, scoring='accuracy', verbose=2, n_jobs=-1)
grid_search.fit(X_train_scaled, y_train)
best_clf = grid_search.best_estimator_
y_pred_best = best_clf.predict(X_test_scaled)
print("Best Parameters:", grid_search.best_params_)
print("Best Accuracy:", accuracy_score(y_test, y_pred_best))
print("Classification Report with Best Parameters:\n", classification_report(y_test, y_pred_best))
结果:
结论
通过上述步骤,可以初步了解红酒数据集的完整性、重复性以及各特征之间的关联关系。这些数据分析步骤对于进一步的数据处理和建模(如分类或回归)至关重要。