在使用 LSTM 之前我需要转换字符串吗?

数据挖掘 喀拉斯 张量流 lstm
2022-03-06 06:28:39

我有一个数据集,其中包含一个带有 URL 的列和另一个带有值 0 或 1 的列,指示它是否是网络钓鱼链接。

在此处输入图像描述

我想使用 LSTM 处理这个数据集。我需要先将字符串列转换为其他数据类型吗?

我希望使用的模型如下所示:

# Model building using the Sequential API
model3 = Sequential()
model3.add(Dense(10, activation='relu',
          kernel_initializer='uniform',input_dim=x3.shape[1]))

# Add a LSTM layer with 128 internal units.
model3.add(layers.LSTM(128))

# Add a Dense layer with 10 units.
model3.add(layers.Dense(10))
2个回答

我需要先将字符串列转换为其他数据类型吗?

是的,这非常重要。神经网络不将原始单词和/或字母作为输入。文本信息必须经过数字处理才能输入模型。

我想了想,想出了三件你可以做的事情:

  1. 正如建议的那样,使用one-hot encoding 。我不喜欢这个选项:one-hot 编码生成非常稀疏的矩阵,这意味着每一步几乎所有维度的变化都非常小。而且,网站数量多得离谱,通过one-hot编码可能无法管理。此外,它并不健壮:您的模型必须在看不见的数据上进行测试,根据定义,这些数据无法使用该技术进行操作。此外,某些网站可能与其他网站或多或少相似,它们对您的模型扮演或多或少相似的角色;但是 one-hot encodind 无法表示它们的差异:如果您计算它们之间的任何距离度量,它们看起来都同样不同。

  2. 假设您正在使用序列,我的主要建议是使用嵌入向量来表示 Web USL 。就像在 NLP 中可以将单词翻译成嵌入向量一样(word2vec 或 glove 就是这种情况),您可以应用相同的技术来表示网站的“相对含义”。通过这种方式,您可以:a) 控制维数,b) 拥有模型所需的非稀疏矩阵。你最终会得到一个完全适合 RNN 的web2vec模型。此外,模型可以毫不费力地学习新的、看不见的网站的含义。这可以通过库(如gensim)或使用 KerasEmbedding()层来完成。

  3. 一个更极端、更耗时的选择是使用字符嵌入仅当您认为网站名称本身包含与您的任务相关的信息时,这才会有用。我不确定是不是这样。字符级嵌入产生非常复杂的模型,但它们的计算成本比其他模型高。而且我不确定它们对您的情况是否有用。

如果让我选择,我会选择选项 2。

最后,让我提示一下:不要在Dense()图层之前放置LSTM()图层。首先,循环层处理顺序数据,然后将它们的输出发送到执行预测的密集层。输出层应该有一个节点 + Sigmoid 激活 + 二元交叉熵损失,或者两个节点 + Softmax 激活 + 分类交叉熵损失。根据你喜欢的。

您可以使用one-hot 编码将您的域编码为 char 数组。那么你的训练样本应该有维度(样本、最长域长度、所有使用的字符)。这是一个代码示例:

import pandas as pd
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, LSTM

# make some fake samples
urls = ['https://datascience.stackexchange.com/', 
        'https://github.com/', 
        'www.google.com/']

labels = [1,0,1]
df = pd.DataFrame(zip(urls, labels), 
                  columns=['domain', 'label'])

# Make it all to a long string
concat_domains = '\n'.join(df['domain']).lower()

# Find all unique characters by using set()
chars = sorted(list(set(concat_domains)))
num_chars = len(chars)

# Build translation dictionaries, 'a' -> 0, 0 -> 'a'
char2idx = dict((c, i) for i, c in enumerate(chars))
idx2char = dict((i, c) for i, c in enumerate(chars))

# Use longest name length as our sequence window
max_sequence_length = max([len(name) for name in df['domain']])

# build dataset with domains as one-hot encoded chars
X = np.zeros((df.shape[0], max_sequence_length, num_chars), dtype=np.bool)
y = df['label'].values

for i, sequence in enumerate(df['domain']):
    for j, char in enumerate(sequence):
        X[i, j, char2idx[char]] = 1


# build a model with input dim: (length of longest domain name, number of unique chars found)
model = Sequential()
model.add(LSTM(64, input_shape=(max_sequence_length, num_chars)))
model.add(Dense(units=1, activation='sigmoid'))

model.compile(loss='binary_crossentropy', optimizer='adam')

# train for 10 epochs
model.fit(X, y, epochs=10)