通过神经网络预测蘑菇(分类)的可食用性
#python #datascience #machinelearning #tensorflow

在这里,我们将为theMushroom Classification Dataset建立分类模型。该模型将分类是否可食用(E)或有毒(P)。其他属性是:
您可以在Kaggle link之后找到所有属性的描述。
首先,让我们导入大熊猫并使用它来读取下载的数据集。然后,我们将显示下载的数据集

m_df = pd.read_csv("/content/mushrooms.csv")
m_df

输出:
Image description
现在我们应该探索数据集:

检查未填充的列值:

m_df.isnull().sum()

输出:

class                       0
cap-shape                   0
cap-surface                 0
cap-color                   0
bruises                     0
odor                        0
gill-attachment             0
gill-spacing                0
gill-size                   0
gill-color                  0
stalk-shape                 0
stalk-root                  0
stalk-surface-above-ring    0
stalk-surface-below-ring    0
stalk-color-above-ring      0
stalk-color-below-ring      0
veil-type                   0
veil-color                  0
ring-number                 0
ring-type                   0
spore-print-color           0
population                  0
habitat                     0
dtype: int64

没有列缺少值。

现在检查数据集的数据类型:

m_df.dtypes

输出:

class                       object
cap-shape                   object
cap-surface                 object
cap-color                   object
bruises                     object
odor                        object
gill-attachment             object
gill-spacing                object
gill-size                   object
gill-color                  object
stalk-shape                 object
stalk-root                  object
stalk-surface-above-ring    object
stalk-surface-below-ring    object
stalk-color-above-ring      object
stalk-color-below-ring      object
veil-type                   object
veil-color                  object
ring-number                 object
ring-type                   object
spore-print-color           object
population                  object
habitat                     object
dtype: object

我们可以看到没有数值列。

分析数据集后,我们应该将其分为两个:标签数据集和功能数据集。

X = m_df.drop("class", axis=1)
y = m_df["class"] 

我们不能训练模型并在同一数据集上测试预测结果,就像学生不应该写他的考试,因此我们必须将数据集分配给测试和培训:< br>

from sklearn.model_selection import train_test_split

# The labels should be numerical so we replace all of the labels 
# with ones and zeros
y.replace("p", 0, inplace=True)
y.replace("e", 1, inplace=True)
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=(0.2))

数据集中的所有值均以分类形式。该模型无法以这种形式从数据中学到任何东西,因此我们应该对其进行编码 - 通过将每个分类值转换为新的分类列,并将二进制值分配为1或0的过程。我们也可能想绘制所有蘑菇样品,以便我们可以更好地看到属性与标签的相关性。在此示例中,我们可以通过缩小尺寸来做到这一点 - 使用PCA。

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer

cat_features = [*X.columns]
cat_transformer = Pipeline(steps=[("onehot", OneHotEncoder(sparse=False)), ("pca", PCA(n_components=2))])

ct = ColumnTransformer(transformers=[("categories", cat_transformer, cat_features)])
ct.fit(X)
X_train_t = ct.transform(X_train)
X_test_t = ct.transform(X_test)

绘制PCA图:

plt.scatter(X_train_t[:, 0], X_train_t[:, 1], alpha=0.4, color="lightblue");

Image description
我们还可以看到不同特征与热图上的标签的相关性:

sns.heatmap(pd.get_dummies(m_df).corr())

Image description

现在我们最终可以开始训练我们的模型。我们只需要不同的标签,因此我们应该使用sigmoid激活函数,因为它将返回我们的值0到1的范围以及使用binary_crossentropy。我们还将使用LearningRateSchedulerCallback来尝试通过分析从(1e-4 * (10**(1/15)))(0.000116591440118)到(1e-4 * (10**(100/15)))(464.1588883361)的不同学习率的损失和准确性来找到理想的学习率。

model = tf.keras.Sequential([
    tf.keras.layers.Dense(10, activation="relu"),
    tf.keras.layers.Dense(30, activation="relu"),
    tf.keras.layers.Dense(1, activation="sigmoid")
])

model.compile(loss="binary_crossentropy", optimizer=tf.keras.optimizers.Adam(), metrics=[tf.keras.metrics.binary_crossentropy, "accuracy"])

lr_cb = tf.keras.callbacks.LearningRateScheduler(lambda epoch: 1e-4 * (10**(epoch/15)))

history = model.fit(X_train_t, y_train, epochs=70, verbose=1,  callbacks=[lr_cb])

我们可以可视化模型的训练过程的history

hist = pd.DataFrame(history.history).drop("binary_crossentropy", axis=1)
hist.plot()

Image description
正如我们在图表上看到的那样,当学习率增加了一定点时,模型的准确性开始下降。
让我们看一下学习率和损失曲线的相关性:

lrs = 1e-4 * (10**(np.arange(0,70)/15)) # generate an array of
# learning rates with the same number of epochs
plt.semilogx(lrs, hist.loss)

Image description
损失从10E-4急剧降低到10E-3。我们应该将TE值更接近曲线的最低点(10E-3),该值将等于0.0097左右(这几乎与Adam的默认学习率完全相同)。
现在,让我们以理想的学习率拟合模型:

model = tf.keras.Sequential([
    tf.keras.layers.Dense(10, activation="relu"),
    tf.keras.layers.Dense(30, activation="relu"),
    tf.keras.layers.Dense(1, activation="sigmoid")
])

model.compile(loss="binary_crossentropy", optimizer=tf.keras.optimizers.Adam(learning_rate=0.0097), metrics=[tf.keras.metrics.binary_crossentropy, "accuracy"])

history = model.fit(X_train_t, y_train, epochs=15, verbose=1)

现在,我们可以使用测试数据集用我们的模型进行预测,并绘制混乱矩阵以更好地可视化结果:

y_pred = np.round(model.predict(X_test_t)[:, 0])
ConfusionMatrixDisplay.from_predictions(y_true=y_test, y_pred=y_pred);

Image description
现在,让我们编写一个函数,该函数将根据模型的预言和实际值返回不同的指标,并使用它来评估我们的模型:

def metrics(y_test, y_pred):
    f1 = f1_score(y_test, y_pred)
    rec = recall_score(y_test, y_pred)
    acc = accuracy_score(y_test,y_pred)
    prec = precision_score(y_test,y_pred)
    return f"Accuracy: {round(acc, 2)}, Precision: {round(prec, 2)}, Recall: {round(rec, 2)}, F1: {round(f1, 2)}"  
metrics(y_test, y_pred)

输出:
Accuracy: 0.94, Precision: 0.96, Recall: 0.93, F1: 0.94
现在我们的模型完成了!希望这篇文章很有帮助,谢谢您的阅读!