具有分类数据的一类支持向量机

Posted

技术标签:

【中文标题】具有分类数据的一类支持向量机【英文标题】:One-Class Support Vector Machine with categorical data 【发布时间】:2021-06-28 11:01:07 【问题描述】:

我正在尝试训练一个机器学习模型来预测车辆控制器区域网络 (CAN) 中的异常消息。这个想法是有一个一类支持向量机 (OCSVM),它将消息频率 (Hz) 作为一个特征,将消息 ID 作为另一个特征(ID 是十六进制的),并为正常数据训练一个 OCSVM,然后预测带有一些恶意消息的其他数据集的异常。问题是我不知道如何预处理 ID。我尝试了以下方法:

对 ID 进行排序,将 ID 重新映射为数值,即 1-27(总共 27 个 ID)。问题:不应将 ID 视为连续的,因为“更高”的 ID 不应影响预测结果。这导致我采用了第二种方法。 将 ID 视为分类数据,通过一些研究,我发现 one-hot 编码是一种转换 ID 的有效方法。

我正在使用 sci-kit learn 作为框架。现在我的代码面临一些问题和疑问:

首先,使用 sklearn OneHotEnconder 转换 ID 时出现错误。将新数据帧导出到 csv 让我看到 ID 现在是一个数组,但采用字符串的形式(见下图)。而且我认为这会导致一些问题。 其次,我不知道或不了解新编码特征将如何用作模型的输入? 第三,我应该对编码值进行标准化/标准化吗?这有什么意义吗? 最后,我在当前的实现中遇到了这个错误(参见下面的错误 + 代码):

非常感谢任何帮助或反馈!

(测试 .csv 的图像)

错误:

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/pandas/core/internals/managers.py", line 1675, in create_block_manager_from_blocks
    make_block(
  File "/usr/local/lib/python3.8/site-packages/pandas/core/internals/blocks.py", line 2732, in make_block
    return klass(values, ndim=ndim, placement=placement)
  File "/usr/local/lib/python3.8/site-packages/pandas/core/internals/blocks.py", line 142, in __init__
    raise ValueError(
ValueError: Wrong number of items passed 27, placement implies 1

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/models/OCSVM.py", line 19, in <module>
    temp_df_train = pd.DataFrame(columns = ["ID"], data = new_train_ID)
  File "/usr/local/lib/python3.8/site-packages/pandas/core/frame.py", line 558, in __init__
    mgr = init_ndarray(data, index, columns, dtype=dtype, copy=copy)
  File "/usr/local/lib/python3.8/site-packages/pandas/core/internals/construction.py", line 238, in init_ndarray
    return create_block_manager_from_blocks(block_values, [columns, index])
  File "/usr/local/lib/python3.8/site-packages/pandas/core/internals/managers.py", line 1687, in create_block_manager_from_blocks
    raise construction_error(tot_items, blocks[0].shape[1:], axes, e)
ValueError: Shape of passed values is (13716, 27), indices imply (13716, 1)

代码:

import pandas as pd 
from sklearn.svm import OneClassSVM
from sklearn.neighbors import LocalOutlierFactor
from sklearn import preprocessing
import matplotlib.pyplot as plt
from numpy import where
import numpy as np

train_data = pd.read_csv("../Data/HCRL_Car-Hacking_Dataset/normal_data_set/normal_frequency_interval.csv") 
test_data = pd.read_csv("../Data/HCRL_Car-Hacking_Dataset/dos_data_set/dos_frequency_interval.csv") 

df_train = train_data[["ID", "Frequency"]]
df_test = test_data[["ID", "Frequency"]]

#------Encoding Categorically (IDs)--------
enc = preprocessing.OneHotEncoder(handle_unknown='ignore')
#Train data
new_train_ID = enc.fit_transform(train_data["ID"].to_numpy().reshape(-1, 1)).toarray()
temp_df_train = pd.DataFrame(columns = ["ID"], data = new_train_ID)
df_train = df_train.drop(["ID"], axis=1)
df_train = pd.concat([df_train, temp_df_train], axis=1)
#Test Data
new_test_ID = enc.fit_transform(test_data["ID"].to_numpy().reshape(-1, 1)).toarray()
temp_df_test = pd.DataFrame(columns = ["ID"], data = new_test_ID)
df_test = df_test.drop(["ID"], axis=1)
df_test = pd.concat([df_test, temp_df_test], axis=1)


df_train.to_csv("onehot.csv")


#Normalization
# df_train[["ID", "Frequency"]] = preprocessing.normalize(train_data[["ID", "Frequency"]])
# df_test[["ID", "Frequency"]] = preprocessing.normalize(test_data[["ID", "Frequency"]])

#Standardization
# scaler = preprocessing.StandardScaler().fit(df_train)
# scaler.transform(df_train)
# scaler.transform(df_test)


# model specification
model = OneClassSVM(kernel="rbf", gamma=0.1, nu=0.1)
#model = LocalOutlierFactor(novelty=True, n_neighbors=20)

#train model
model.fit(df_train)
prediction = model.predict(df_test)

#Plotting
plt.xlabel("Message ID")
plt.ylabel("Frequency (Hz)")


outlier_index = where(prediction == -1) 
outlier_values = df_test.iloc[outlier_index]
print(test_data[["ID", "Frequency"]].iloc[outlier_index]) #I want to see what IDS are anomal
plt.scatter(df_train.ID,df_train.Frequency);
plt.scatter(outlier_values["ID"],outlier_values["Frequency"])
plt.show()

【问题讨论】:

【参考方案1】:

我复制了图像中显示的数据集并创建了一个函数,给定具有频率和 ids 的数据帧,返回具有频率和生成的 one-hot-vector 列的数据帧。这样,您可以将函数返回的数据帧传递给 OCSVM 进行训练。在规范化问题上,我认为比较规范化与非规范化比较好,这样您就可以了解 OCSVM 在每种数据类型上的表现。

提示:将训练和测试数据合并到一个数据帧中以使用我给你的功能,然后将返回的数据帧再次分成两个数据帧(训练和测试)。

import pandas as pd

df = pd.DataFrame(columns=['Frequency', 'ID'])
df = df.append('Frequency' : 15, 'ID' : '1', ignore_index=True)
df = df.append('Frequency' : 1, 'ID' : '2', ignore_index=True)
df = df.append('Frequency' : 1, 'ID' : '3', ignore_index=True)
df = df.append('Frequency' : 15, 'ID' : '4', ignore_index=True)
df = df.append('Frequency' : 15, 'ID' : '5', ignore_index=True)
df = df.append('Frequency' : 15, 'ID' : '6', ignore_index=True)
df = df.append('Frequency' : 15, 'ID' : '7', ignore_index=True)
df = df.append('Frequency' : 15, 'ID' : '8', ignore_index=True)
df = df.append('Frequency' : 8, 'ID' : '9', ignore_index=True)
df = df.append('Frequency' : 15, 'ID' : '10', ignore_index=True)
df = df.append('Frequency' : 15, 'ID' : '11', ignore_index=True)
df = df.append('Frequency' : 15, 'ID' : '12', ignore_index=True)
df = df.append('Frequency' : 15, 'ID' : '13', ignore_index=True)
df = df.append('Frequency' : 15, 'ID' : '14', ignore_index=True)
df = df.append('Frequency' : 15, 'ID' : '15', ignore_index=True)

from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
import numpy as np

def df_onehot(df, num_ids):
  features_cat = ['ID']

  pipeline_cat = Pipeline(steps=[('onehot', OneHotEncoder())])

  transf = ColumnTransformer(transformers=[('transformacao categorica', pipeline_cat, features_cat)])

  dt = transf.fit_transform(df)

  names = ['Frequency']
  for id in range(1,num_ids+1):
    tring = 'Id'
    names.append(tring)

  data_ok = np.concatenate([[df['Frequency'].to_list()], dt.toarray().T])

  df_ok = pd.DataFrame(data = data_ok.T, columns=names)
  df_ok

  return df_ok

df_train = df_onehot(df, 15)

【讨论】:

以上是关于具有分类数据的一类支持向量机的主要内容,如果未能解决你的问题,请参考以下文章

SVM支持向量机

支持向量机分类及在R中实现

支持向量机

第6章 支持向量机

基于MATLAB的SVM支持向量机的数据分类仿真,包括训练和测试

具有 3 个结果的支持向量机 [关闭]