将简单分类器和神经网络应用于实际数据
许多用于在线研究目的的流行数据集是干净和平衡的,在响应和预测变量之间具有强相关性。然而,真实世界的数据可能远非如此理想化的图景。因此,在研究数据集上提供良好结果的模型可能会给实际数据带来不好的结果。
在这种特殊情况下,我将研究一个包含PC性能不同指标的数据集,以创建一个模型来预测给定设备何时需要重新映像(reimage)的时间表。在现实世界中,这种模式的做法正确并且信心十足,可以帮助公司和个人用户节省大量时间,避免可能由PC故障导致的长时间停机。我会做一些标准的EDA步骤,并使用几个着名的分类器,以及一个简单的神经网络模型。项目代码是用Python编写的。
探索数据集
我将使用的数据集包含多个PC测试性能指标,从物理/虚拟内存和RAM使用到软件错误。预测变量(“zone”)表示设备的风险区域 - 即给定设备需要重新映像时间 - 并且包含代表10天时间段的从0到6的区域:
- Zone 0:设备健康(下一个reimage 的日期是NaN)
- Zone 1: 设备将在接下来的0-10天内reimage
- Zone 2: 设备将在接下来的11-20天内reimage
- Zone 3: 设备将在接下来的21-30天内reimage
- Zone 4: 设备将在接下来的31-40天内reimage
- Zone 5: 设备将在接下来的41-50天内reimage
- Zone 6: 设备将在接下来的51-60天内reimage
该数据集有5,609,148行和12个特征(输入变量)存储在.csv文件中。
变量及其级别的详细描述可以在这里找到(https://github.com/mamnunam/Springboard_Data_Science_track/blob/master/Capstone_2/dataset_description.txt)。
我们来探索一下数据集。我们将开始加载分析和预测所需的所有库:
#Pandas for dataframes
import pandas as pd
#Changing default display option to display all columns
pd.set_option('display.max_columns', 21)
#Numpy for numerical computing
import numpy as np
#Matplotlib for visualization
import matplotlib.pyplot as plt
#Display plots in the notebook
%matplotlib inline
#Seaborn for easier visualization
import seaborn as sns
#Stats package for statistical analysis
from scipy import stats
#Machine learning packages
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.model_selection import train_test_split, cross_val_score, cross_val_predict, GridSearchCV
from sklearn.pipeline import make_pipeline, Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import roc_curve, roc_auc_score, auc, accuracy_score, confusion_matrix, classification_report, cohen_kappa_score
from sklearn.utils import resample
from sklearn.dummy import DummyClassifier
from sklearn.model_selection import KFold
#Neural Networks packages
from keras.layers import Dense, Dropout
from keras.models import Sequential
from keras.utils import to_categorical
from keras.wrappers.scikit_learn import KerasClassifier
加载数据集
df = pd.read_csv('/sw_health_raw_data.csv', parse_dates=True)
我们来看看数据集的整体特征
大多数变量都是数字。我们来看看数据的第一行和最后五行:
数据集的前5行
数据集的最后5行
两端的数据看起来一致,并没有明显的错误。'next_reimage'列中有NaNs,对应于zone = 0。由于'next_reimage'定义了'zone'变量,因此我们不需要将两者都保留在数据集中,并且只能保留'zone'变量为了预测模型的建立。
现在我们来检查一下变量是否有缺失值:
#Checking for NaNs
for i in df.columns:
print(i, ": ", df.loc[:,i].isnull().values.any())
检查数据集中的NaN
数据中没有缺失值,除了预期的'next_reimage'列。数据集描述中提到了'date'变量,因此也没有缺失值。
在研究变量的分布之前,让我们先做一些清理。我将'日期'转换为日期时间对象并删除'next_reimage'变量。此外,让我们将“Zone”变量的0级别重命名为“7”,以便健康级别的变化看起来更合乎逻辑。
#清理数据集
df_cleaned = df.copy()
df_cleaned ['date'] = pd.to_datetime(df_cleaned.date)
df_cleaned = df_cleaned.drop('next_reimage',axis = 1)
df_cleaned.zone.replace(0,7 ,inplace = True)
接下来,让我们看看数据集中数值变量的分布:
数值变量的分布
变量“free_physical_memory”、“free_virtual_memory”和“daily_average_ram”都有最小值为0,这是没有意义的。无论系统的性能如何,在现实生活中这些值的最小值不能为零。接下来,“average_time_since_last_boot”具有负值,这也没有意义。daily_average_ram的最大值是1418.6%,这是不可能的。
让我们看看发生这种情况的事例的数量:
上述所有情况都表示数据集的一小部分,可以删除。让我们放弃那些实例:
#Dropping the erroneous instances
df_cleaned = df_cleaned.loc[(df_cleaned['free_physical_memory'] > 0)]
df_cleaned = df_cleaned.loc[(df_cleaned['free_virtual_memory'] > 0)]
df_cleaned = df_cleaned.loc[(df_cleaned['daily_average_ram'] <= 100)]
df_cleaned = df_cleaned.loc[(df_cleaned['average_time_since_last_boot'] > 0)]
数据集中表示的时间段为3个月:
接下来,让我们看看每个响应变量(“zone”)的级别是如何分布的。为这一数量的数据绘制单个的条形图需要花费大量的计算时间,因此我们将使用汇总表和这些分布的图表来评估变量的分布属性。首先,让我们看一下区域的响应数量:
按区域计算行数
在这里,我们遇到了真实世界数据集的第一个标志:几乎96%的数据集条目属于区域7(PC没有问题),这是合乎逻辑的 。实际上,区域1到5仅占所有数据的0.3%。这使得数据集非常不平衡,这使得标准模型评估指标如准确性得分与这种情况关系不大。在区域1-5之间,每个区域的行数大致相同,区域6的观察值比前面的5个区域多10倍。
现在让我们看看通过绘制汇总表和图形,每个区域变量的平均值是否存在显着差异:
每区域变量的意义
#Converting a 'groupby' object to a DataFrame
means = df_cleaned.groupby('zone').mean().reset_index()
#Plotting the charts
plt.figure(figsize=(17,16))
plt.subplot(4,2,1)
plt.title('Mean of free physical memory by zones')
plt.plot('zone', 'free_physical_memory', data= means, marker='o', linestyle='dashed')
plt.ylabel('free physical memory')
plt.xlim(7,1)
plt.subplot(4,2,2)
plt.title('Mean of free virtual memory by zones')
plt.plot('zone', 'free_virtual_memory', data= means, marker='o', linestyle='dashed')
plt.ylabel('free virtual memory')
plt.xlim(7,1)
plt.subplot(4,2,3)
plt.title('Mean of daily average ram by zones')
plt.plot('zone', 'daily_average_ram', data= means, marker='o', linestyle='dashed')
plt.ylabel('daily average ram')
plt.xlim(7,1)
plt.subplot(4,2,4)
plt.title('Mean of daily ram std dev by zones')
plt.plot('zone', 'daily_std_dev_ram', data= means, marker='o', linestyle='dashed')
plt.ylabel('daily ram std dev')
plt.xlim(7,1)
plt.subplot(4,2,5)
plt.title('Share of observations with Windows events by zones')
plt.plot('zone', 'windows_events_count', data= means, marker='o', linestyle='dashed')
plt.ylabel('observations with windows events')
plt.xlim(7,1)
plt.subplot(4,2,6)
plt.title('Share of observations with BIOS error by zones')
plt.plot('zone', 'has_bios_error', data= means, marker='o', linestyle='dashed')
plt.ylabel('observations with BIOS error')
plt.xlim(7,1)
plt.subplot(4,2,7)
plt.title('Mean of driver crash count by zones')
plt.plot('zone', 'driver_crash_count', data= means, marker='o', linestyle='dashed')
plt.xlabel('zone')
plt.ylabel('driver crash count')
plt.xlim(7,1)
plt.subplot(4,2,8)
plt.title('Mean of avg time since last boot by zones')
plt.plot('zone', 'average_time_since_last_boot', data= means, marker='o', linestyle='dashed')
plt.xlabel('zone')
plt.ylabel('avgt time')
plt.xlim(7,1)
plt.tight_layout()
plt.show()
基于上述,我们可以做出几点观察。首先,随着设备接近临界状态(区域1),空闲物理内存的平均量趋于略微增加,并且随着设备离开区域7-6进入区域5,空闲虚拟内存量显着下降。均值的日均RAM值在设备接近临界状态时下降约6pp,而该平均值的标准差增加。
在第7区中约95%的观测值具有Windows事件,而其他区域中该变量接近99%。随着设备进入5-1区,观察到的具有BIOS错误的观测份额显着增加,因此这个变量可能成为即将到来的设备重新映像的有力预测器。
最后,当设备接近临界状态时,驱动器崩溃的平均数实际上会减少。自上次启动以来平均时间的平均值也大幅下降,这意味着接近临界状态的设备往往会更频繁地重新启动。
一般来说,所有预测因子在“健康”(7-6)和“不健康”(5-1)区域之间的平均值中表现出明显的差异,所以将它们全部纳入预测模型是合理的。然而,区域之间差异的绝对值并不大,这可能会影响预测的准确性。
现在,让我们用皮尔逊的偏度系数来考察变量按区域分布的偏度:
#Calculating Pearson's coefficient of skewness for the predictors vs. the levels of the 'zone' variable
3*(df_cleaned.groupby('zone').mean() - df_cleaned.groupby('zone').median())/df_cleaned.groupby('zone').std()
偏差的分布
对于所有区域,预测变量的分布基本上是倾斜的,这意味着存在大量的异常值,并且大多数变量具有正偏差。我们来看看这些变量的区域图。Pandas的标准boxplot()函数不会产生令人满意的结果,所以我将不得不为56个图表创建一个手动网格。我还必须限制x轴,以便删除一些过度缩小图表的异常值。
plt.figure(figsize=(30,25))
counter = 1
for i in range(1,8):
plt.subplot(7,8,counter)
plt.title('free_physical_memory')
sns.boxplot(x='free_physical_memory', data=df_cleaned.loc[df_cleaned['zone'] == i])
plt.ylabel('zone ' + str(i))
plt.xlabel(' ')
plt.xlim(0, 256156)
counter += 1
plt.subplot(7,8,counter)
plt.title('free_virtual_memory')
sns.boxplot(x='free_virtual_memory', data=df_cleaned.loc[df_cleaned['zone'] == i])
plt.xlabel(' ')
plt.xlim(0, 381930)
counter += 1
plt.subplot(7,8,counter)
plt.title('daily_average_ram')
sns.boxplot(x='daily_average_ram', data=df_cleaned.loc[df_cleaned['zone'] == i])
plt.xlabel(' ')
plt.xlim(0,100)
counter += 1
plt.subplot(7,8,counter)
plt.title('daily_std_dev_ram')
sns.boxplot(x='daily_std_dev_ram', data=df_cleaned.loc[df_cleaned['zone'] == i])
plt.xlabel(' ')
plt.xlim(0,100)
counter += 1
plt.subplot(7,8,counter)
plt.title('windows_events_count')
sns.countplot(x='windows_events_count', data=df_cleaned.loc[df_cleaned['zone'] == i])
plt.xlabel(' ')
counter += 1
plt.subplot(7,8,counter)
plt.title('has_bios_error')
sns.countplot(x='has_bios_error', data=df_cleaned.loc[df_cleaned['zone'] == i])
plt.xlabel(' ')
counter += 1
plt.subplot(7,8,counter)
plt.title('driver_crash_count')
sns.boxplot(x='driver_crash_count', data=df_cleaned.loc[df_cleaned['zone'] == i])
plt.xlabel(' ')
plt.xlim(0,300)
counter += 1
plt.subplot(7,8,counter)
plt.title('average_time_since_last_boot')
sns.boxplot(x='average_time_since_last_boot', data=df_cleaned.loc[df_cleaned['zone'] == i])
plt.xlabel(' ')
plt.xlim(0, 11991245)
counter += 1
plt.tight_layout()
plt.show()
可以看出,所有变量的分布实际上对于区域1至5是相同的。区域6和7在变量'free_physical_memory','free_virtual_memory','daily_std_dev_ram','driver_crash_count'和'average_time_since_last_boot'中具有明显更多的异常值。区域6-7的'daily_average_ram'分布比其他区域更为对称,并向更大的值移动。另一方面,'daily_std_dev_ram'的平均值小于1-5区。最后,'has_bios_error'变量的分布与区1-5相比是颠倒的 - 大多数区域6-7设备没有BIOS错误。
统计分析
我们来绘制数据集的关联热图:
#Calculate correlations between the features and predictor
correlations = df_cleaned.corr()
#Make the figsize 7 x 6
plt.figure(figsize=(7,6))
#Plot heatmap of correlations
_ = sns.heatmap(correlations, cmap="Greens", annot=True)
数据的相关热图
可以看出,“区域”变量与数据集中的预测因子具有非常小的相关性,这并不令人惊讶,因为随着设备从一个区域向另一个区域前进,预测变量值的绝对值变化很小。与此同时,一些预测因素具有实质相关性:'free_virtual_memory'与'free_physical_memory'强烈正相关,这是合理的,因为较大的虚拟内存会降低系统对空闲物理内存的需求。'daily_average_ram'和'daily_std_dev_ram'与'free_physical_memory'负相关,这也是有意义的,因为如果可用物理内存的数量增加,平均RAM(物理内存)使用量将减少。最后,'daily_average_ram'和'daily_std_dev_ram'之间有一个小的正相关,
对数据集进行下取样
如前所述,属于区域1至5的观察值仅占所有数据的0.3%,这使得数据集非常不平衡。解决不平衡数据集有多种可能的方法,但是,考虑到我们的数据集大小(5.6M观察值)和计算限制(建模在具有i7处理器和16Gb RAM的计算机上完成),我会使用下采样方法。这种方法也是有意义的,因为区域6-7的值的分布相对平衡,并且具有几百万个观察值与几千个随机采样的观测值在我们的情况下不会增加太多价值。
如果使用基于云计算的并行化计算资源,数据集可以保持原样,但这种方法超出了当前研究项目的范围。
为了将类别6-7与类别1-5相提并论,我们将随机抽取类别6和类别7的5,000个观测值,并创建一个新的下采样数据集。
#Separating zones 1 and 5
df_1_5 = df_cleaned[((df_cleaned.zone!=6) & (df_cleaned.zone!=7))]
#Separating zones 6 and 7
df_6 = df_cleaned[df_cleaned.zone==6]
df_7 = df_cleaned[df_cleaned.zone==7]
#Downsampling zones 6-7
df_6_downsampled = resample(df_6, replace=True, n_samples=5000, random_state=42)
df_7_downsampled = resample(df_7, replace=True, n_samples=5000, random_state=42)
#Concatenating into one downsampled data frame
df_downsampled = pd.concat([df_1_5, df_6_downsampled, df_7_downsampled])
#Checking the resulting counts of observations
df_downsampled.groupby('zone').count()
检查下采样数据集的行数
最后,我们将下采样数据集保存到一个文件中。此文件可在GitHub找到(https://github.com/mamnunam/Springboard_Data_Science_track/blob/master/Capstone_2/downsampled_data.csv)。
#将文件保存到
df_downsampled.to_csv('downsampled_data.csv')
拟合预测模型
Logistic回归
第一个也是最简单的预测模型是Logistic回归。由于它是一个二元分类器,因此我们需要使用one-vs-rest(OVR)方法分别预测每个区域的概率。我们假设每个区域都独立于另一个区域(即,一个设备的区域不依赖于另一个设备的区域)。我们将使用StandardScaler来标准化这些特征。
#Splitting the variables into predictor and target variables. We need to drop 'pcid' and 'date' variables,
#as those variables are not relevant for the purpose of prediction.
X = df_downsampled.drop(['zone', 'pcid', 'date'], axis=1)
y = df_downsampled.zone
#Creating a pipeline with the StandardScaler and one-vs-rest logistic regression object
pipeline = make_pipeline(StandardScaler(), LogisticRegression(random_state=42, multi_class='ovr'))
#Calculating an array of cross-validated scores
scores = cross_val_score(pipeline, X, y, cv=10)
#Displaying the mean prediction accuracy for 95% confidence interval
print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))
这给出了0.27(+/- 0.02)的平均准确度。这是一个非常低的结果,比这些模型通常在干净和平衡的研究数据集上产生的结果低几倍。让我们看看分类报告来评估不同类别的精确度和召回率。为此,我们需要将数据拆分为训练和测试集。
#Splitting the data into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y)
#Fitting the model
pipeline.fit(X_train, y_train)
#Creating the classification report
print(classification_report(y_test, pipeline.predict(X_test)))
Logistic回归分类报告
该模型完全错过了2-5级,并且对于预测类别7的效果最好,但精度和召回率的值仍然很低。由于数据集显着的初始不平衡,准确性评分或精度/召回等指标可能不是评估模型质量的最佳指标。让我们看一下Cohen的Kappa分数作为评估预测质量的替代指标:
尽管Kappa分数的大小的解释各不相同,但从任何角度来看,0.12都非常低,并且表示预测质量很差。因此,Logistic回归似乎不是预测PC健康区的好模型。
在尝试其他预测模型之前,让我们拟合一个虚拟分类器并与我们的Logistic回归模型进行比较:
#Setting up the pipeline
pipeline_dummy = make_pipeline(StandardScaler(), DummyClassifier(random_state=42))
#Calculating an array of cross-validated scores
scores_dummy = cross_val_score(pipeline_dummy, X, y, cv=10)
#Displaying the mean prediction accuracy for 95% confidence interval
print("Accuracy: %0.2f (+/- %0.2f)" % (scores_dummy.mean(), scores_dummy.std() * 2))
这产生了0.15(+/- 0.01)的精度,其表现比虚拟分类器更差。这证实Logistic回归模型不适用于该数据集。
随机森林和梯度提升
接下来,让我们尝试随机森林和梯度提升,因为这些模型通常为分类问题提供良好的预测质量。我将使用一套“经验法则”参数来为模型选择最佳的参数。
#Setting up pipelines with a StandardScaler function to normalize the variables
pipelines = {
'rf' : make_pipeline(StandardScaler(),
RandomForestClassifier(random_state=42, class_weight='balanced')),
'gb' : make_pipeline(StandardScaler(),
GradientBoostingClassifier(random_state=42))
}
#Setting up the "rule of thumb" hyperparameters for the Random Forest
rf_hyperparameters = {
'randomforestclassifier__n_estimators': [100, 200],
'randomforestclassifier__max_features': ['auto', 'sqrt', 0.33]
}
#Setting up the "rule of thumb" hyperparameters for the Gradient Boost
gb_hyperparameters = {
'gradientboostingclassifier__n_estimators': [100, 200],
'gradientboostingclassifier__learning_rate': [0.05, 0.1, 0.2],
'gradientboostingclassifier__max_depth': [1, 3, 5]
}
#Creating the dictionary of hyperparameters
hyperparameters = {
'rf' : rf_hyperparameters,
'gb' : gb_hyperparameters
}
#Creating an empty dictionary for fitted models
fitted_alternative_models = {}
# Looping through model pipelines, tuning each with GridSearchCV and saving it to fitted_logreg_models
for name, pipeline in pipelines.items():
#Creating cross-validation object from pipeline and hyperparameters
alt_model = GridSearchCV(pipeline, hyperparameters[name], cv=10, n_jobs=-1)
#Fitting the model on X_train, y_train
alt_model.fit(X_train, y_train)
#Storing the model in fitted_logreg_models[name]
fitted_alternative_models[name] = alt_model
#Printing the status of the fitting
print(name, 'has been fitted.')
#Displaying the best_score_ for each fitted model
for name, model in fitted_alternative_models.items():
print(name, model.best_score_ )
随机森林模型的得分为0.377969,而对于梯度增强模型,得分为0.341480。测试数据集的得分非常接近训练数据集的得分,所以模型在两个数据集上的表现都适中,比虚拟分类器好2倍以上。得分最高的模型参数:
最好的随机森林模型的参数
最佳模型的混淆矩阵:
#创建混淆矩阵
pd.crosstab(y_test,fitted_alternative_models ['rf']。predict(X_test),rownames = ['True'],colnames = ['Predicted'],margin = True)
随机森林模型的混乱矩阵
分类报告
该模型检测所有区域(与Logistic回归模型不同),对区域6-7具有最高的精确度和召回率。最后,我们来看看Kappa评分:
得分明显好于Logistic回归模型,但仍不是很高。现在让我们尝试一种更复杂的建模方法。
神经网络模型
基于神经网络的模型在机器学习中被广泛用于分类目的,尽管它们通常需要大量的计算能力。为了比较NN模型的性能和上面测试的模型的性能,我将建立一个简单的NN模型,利用几个“经验法则”方法来最小化所需的计算。
1)隐藏层的数量:关于确定最佳隐藏层数的方法的观点不同,但它看起来像是一般情况下第二层(或第三层等)隐藏层的性能改善的情况非常多少数。一个隐藏层通常足以解决大多数问题,因此我将在模型中使用一个隐藏层。
2)隐藏层中的神经元数目:有一些经验性的“经验法则”来定义这个数字,最常见的方法之一是取数字,这个数字在输入大小和输出大小之间层。我将使用10个神经元的图层。
3)Dropout:为了控制潜在的过度拟合,我将使用Dropout正则化技术,在训练期间忽略随机选择的神经元。我会在输入层之后和隐藏层之后添加一个Dropout层,使用20%的“经验法则”概率,这意味着每5个输入中有1个会随机从每个更新周期中排除。
4)精度指标:为了将NN与其他模型进行比较,我首先看一下10倍交叉验证平均的标准精度指标。为了提高计算效率,我会在10个epochs内完成。大多数深度学习论文基于前5个分类准确性度量来报告模型性能,该度量衡量在前k(在这种情况下为5)预测中的正确预测的准确度。我将计算这个度量以作比较。在Keras中使用Kappa分数并不直接,我将在后端使用Kappa分数,所以在这种情况下,我将跳过计算Kappa分数。
考虑到上述情况,让我们拟合一个简单的神经网络模型:
#Setting the seed
np.random.seed(42)
#Separating predictors into a variable
X_upd = df_downsampled.drop(['zone', 'pcid', 'date'], axis=1)
#Standardazing the predictors
scaler = StandardScaler()
predictors = pd.DataFrame(scaler.fit_transform(X_upd)).as_matrix()
#"One hot" encode for zones and converstion to dummy features
target = to_categorical(df_downsampled.zone.astype(int) - 1, num_classes=7)
#Defining input shape
n_cols=predictors.shape[1]
#Defining the model
def nn_model():
model = Sequential()
model.add(Dense(10, activation='relu', input_shape=(n_cols,)))
model.add(Dropout(0.2))
model.add(Dense(10, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(7, activation='softmax'))
#Compiling the model
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
return model
estimator = KerasClassifier(build_fn=nn_model, epochs=10, batch_size=10, verbose=0)
kfold = KFold(n_splits=10, shuffle=True, random_state=42)
results = cross_val_score(estimator, predictors, target, cv=kfold)
print("Accuracy score: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))
这给出了0.2725(+/- 0.060)的Accuracy 分数,这比使用随机森林和梯度增强模型获得的更差。低分的原因之一可能是数量较少的时代,但使用交叉验证计算更多的epochs会在PC上花费太多时间。另外,我们的下采样数据集非常小,因此在更大的数据集上运行模型可以产生更好的结果。最后,在这种情况下,隐含层和神经元数量的“经验法则”可能不是最好的。让我们尝试增加epochs的数量,同时将数据分成训练和测试集(67%训练/ 33%测试)。我还将计算前5分类准确性度量。
#Setting the seed
np.random.seed(42)
#Defining the model
model = Sequential()
model.add(Dense(10, activation='relu', input_shape=(n_cols,)))
model.add(Dropout(0.2))
model.add(Dense(10, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(7, activation='softmax'))
import keras.backend as K
def top_k_categorical_accuracy(y_true, y_pred, k=5):
return K.mean(K.in_top_k(y_pred, K.argmax(y_true, axis=-1), k), axis=-1)
#Compiling the model
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=[top_k_categorical_accuracy, 'accuracy'])
#whether to shuffle the training data before each epoch
fitted_model = model.fit(predictors, target, validation_split=0.33, epochs=50, batch_size=10, shuffle=True, verbose=0)
基于上述模型,我们来看看模型的精度和损失函数如何随着epochs的数量而变化:
plt.figure(figsize=(20,5))
plt.subplot(1,3,1)
#Plotting accuracy score for train and validation sets
plt.plot(fitted_model.history['top_k_categorical_accuracy'])
plt.plot(fitted_model.history['val_top_k_categorical_accuracy'])
plt.title('Accuracy score dynamic')
plt.ylabel('Accuracy')
plt.ylim(0, 1)
plt.xlabel('Epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.subplot(1,3,2)
#Plotting top-5 categorical accuracy for train and validation sets
plt.plot(fitted_model.history['top_k_categorical_accuracy'])
plt.plot(fitted_model.history['val_top_k_categorical_accuracy'])
plt.title('Top-5 categorical accuracy dynamic')
plt.ylabel('Accuracy')
plt.ylim(0, 1)
plt.xlabel('Epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.subplot(1,3,3)
#Plotting loss function dynamic for train and validation sets
plt.plot(fitted_model.history['loss'])
plt.plot(fitted_model.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.tight_layout()
plt.show()
Model’s accuracy metrics and loss function dynamic
图表显示训练集的分数在几个epochs内几乎达到100%,而测试集的分数保持非常接近于零,并且随着epochs的数量仅略有增加。同时,模型损失迅速增加到20个epochs,然后保持在同一水平。其中一个主要原因可能是测试集的体积小,以及整体数据集小。
它看起来并不像在更多时代测试模型是有意义的,但我们可以尝试用不同的训练/测试分割来测试它:
#Setting the seed
np.random.seed(42)
#Defining the model
model2 = Sequential()
model2.add(Dense(10, activation='relu', input_shape=(n_cols,)))
model2.add(Dropout(0.2))
model2.add(Dense(10, activation='relu'))
model2.add(Dropout(0.2))
model2.add(Dense(7, activation='softmax'))
import keras.backend as K
def top_k_categorical_accuracy(y_true, y_pred, k=5):
return K.mean(K.in_top_k(y_pred, K.argmax(y_true, axis=-1), k), axis=-1)
#Compiling the model
model2.compile(loss='categorical_crossentropy', optimizer='adam', metrics=[top_k_categorical_accuracy, 'accuracy'])
#whether to shuffle the training data before each epoch
fitted_model2 = model2.fit(predictors, target, validation_split=0.4, epochs=50, batch_size=10, shuffle=True, verbose=0)
plt.figure(figsize=(20,5))
plt.subplot(1,3,1)
#Plotting accuracy score for train and validation sets
plt.plot(fitted_model2.history['top_k_categorical_accuracy'])
plt.plot(fitted_model2.history['val_top_k_categorical_accuracy'])
plt.title('Accuracy score dynamic')
plt.ylabel('Accuracy')
plt.ylim(0, 1)
plt.xlabel('Epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.subplot(1,3,2)
#Plotting top-5 categorical accuracy for train and validation sets
plt.plot(fitted_model2.history['top_k_categorical_accuracy'])
plt.plot(fitted_model2.history['val_top_k_categorical_accuracy'])
plt.title('Top-5 categorical accuracy dynamic')
plt.ylabel('Accuracy')
plt.ylim(0, 1)
plt.xlabel('Epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.subplot(1,3,3)
#Plotting loss function dynamic for train and validation sets
plt.plot(fitted_model2.history['loss'])
plt.plot(fitted_model2.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.tight_layout()
plt.show()
测试子集的准确性得分明显较高,而具有较大测试子集的模型的损失增加的速度稍慢,因此在更大或完整的数据集上检查模型的性能肯定有意义。
总而言之,使用标准“经验法则”参数配置的神经网络模型比随机森林或梯度增强模型执行得更差,并且用于神经网络模型的训练和测试分裂的准确性的差异更加剧烈。尽管如此,一个精细调整的神经网络模型可能会产生更好的性能,但是这种模型需要使用基于云计算的并行化计算功能对整个数据集进行训练,这超出了该项目的范围。另外,可以使用更细致的层数微调,神经元和其他参数来获得更好的结果。
结论
随机森林模型在精度和Kappa评分方面都表现出了其他模型的最佳性能。这些分数的绝对值很低,因此这个模型很难用来预测PC在任何现实情况下的健康状况。尽管如此,该模型的性能几乎是虚拟分类器的2倍,因此可以对其进行微调和改进,以产生更好的结果。此外,如上所述,神经网络模型的性能不如stellar,通过对模型进行全数据集的训练和对模型参数的微调,可以获得可能更好的结果。最后,还有一个额外的机会,虽然计算量很大,但可能是几个预测模型的组合。
为了允许更多的实验和更快的结果,以上建议的所有改进都应该利用基于云的并行计算,因为在单个PC上拟合此类分类模型(尤其是在试图找到最佳的模型参数和学习率时)可能是一项艰巨的任务(如果不是几乎不现实的话)。
一般来说,上述研究项目展示了“开箱即用”和标准化模型在真实数据集上的表现,而且,毫不奇怪,这些模型的准确率比通常在干净、准备充分的研究数据集中观察到的准确率低好几倍。