美赛C题纪实

本文介绍了作者在美赛中使用LSTM神经网络进行预测的经验,包括模型构建、超参数调优,并探讨了单个单词的特征提取方法,如字符编码、WordEmbeddings和WordNet的使用。此外,还提到了使用K-means++进行聚类和后续的神经网络模型构建,以对数据进行分类。
摘要由CSDN通过智能技术生成

提示:这篇是美赛结束发的!!!!!!!没有作弊,没有参考任何网上思路!!!!!仅为自己记录教训和为他人提供代码案例


前言

2.18
这一题是博主从头开始学自然语言处理的杰作,中间用实验室服务器建环境建了半天都建不好,用kaggle立马奏效,心态大崩,特别是17号出六级成绩心态更崩,糟糕的最近…

2.21
美赛总算打完了,整理一下所犯的错误和教训,总结一下查到的库和方法,还是得踩着以前自己的肩膀慢慢向上,后面研究生阶段接触神经网络不会少。


一、LSTM神经网络预测

一开始想用pytorch来做,可是代码总是出问题,没打过代码很难受了,好在之前用过keras…keras简直就是神经网络建模的申请,除了它我还不知道怎么在GPU上跑其他一切都好。下面是我LSTM神经网络预测的核心代码示例:

# 创建并训练LSTM模型
model = Sequential()
# model.add(LSTM(units=50, return_sequences=True, input_shape=(trainX.shape[1], trainX.shape[2])))
# model.add(Dropout(0.2))
# model.add(LSTM(units=50, return_sequences=True))
# model.add(Dropout(0.2))
# model.add(LSTM(units=50))
# model.add(Dropout(0.2))
# model.add(Dense(units=1))
model.add(LSTM(64, return_sequences=True, input_shape=(trainX.shape[1], trainX.shape[2])))
# model.add(Dropout(0.3))
# model.add(LSTM(32, return_sequences=True))
# model.add(Dropout(0.35))
# model.add(LSTM(16))
model.add(Dense(1, kernel_regularizer=regularizers.l2(0.01)))
# model = get_model_deep((trainX.shape[1], trainX.shape[2]))
model.compile(loss='mse', optimizer='adam',metrics=['mse'])
model.fit(trainX, trainY, epochs=50, batch_size=1, verbose=1,)

可以说,你想要在神经网络上加一层什么,你就直接add

1.1.超参数调优

选择适合自己的LSTM模型超参数需要综合考虑多个方面,包括模型架构、损失函数、优化器、学习率、batch size、epoch 等参数。下面是一些常用的调参技巧和策略:

调整模型架构:包括 LSTM 层数、神经元个数、激活函数、Dropout 层的位置和参数等。
选择合适的损失函数:根据具体的问题选择适合的损失函数,比如 MSE、MAE、RMSE、交叉熵等。
选择合适的优化器:常用的优化器包括 SGD、Adam、RMSprop、Adagrad 等,需要根据具体的问题选择。
调整学习率:如果学习率设置过大,可能会导致训练不稳定;如果学习率设置过小,可能会导致收敛速度过慢。可以使用 learning rate scheduler 等技术来调整学习率。
调整 batch size:一般来说,batch size 越大,训练速度越快,但是内存消耗也会增加;batch size 越小,训练速度越慢,但是内存消耗也会减小。需要根据具体情况来选择合适的 batch size。
调整 epoch:epoch 越大,模型会更加充分地学习数据,但是也会增加过拟合的风险。需要根据验证集的表现和训练集的表现综合考虑选择合适的 epoch。
在进行调参时,可以使用交叉验证等技术来评估模型的性能,同时还可以使用一些自动化的调参工具,比如 Grid Search、Random Search、Bayesian Optimization 等。

二、对单个单词的特征提取

2.1.可能的提取方法

如果只有一个五个字符的单词,并且没有上下文信息可用,那么提取单词特征的方法将会受到限制。下面是一些可能的特征提取方法:

1.字符频率特征:将单词视为一个字符序列,并统计每个字符在单词中出现的频率。这种方法可以用于区分不同类型的单词,例如元音和辅音比例,或者特定字母的频率。

2.字符n-gram特征:将单词视为一个字符序列,提取不同长度的字符n-gram作为单词的特征。例如,提取所有长度为2或3的字符n-gram可以捕捉单词的部分语义信息,例如前缀和后缀。

3.字符编码特征:将单词中的每个字符编码为数字或二进制向量,作为单词的特征。这种方法可以保留单词的字符信息,但不太适合区分不同类型的单词。

4.字符形态特征:将单词视为由前缀、后缀和词干等构成的结构,并提取这些部分的特征。例如,提取单词的词干长度、前缀或后缀的形态特征等,可以帮助区分不同类型的单词。

2.2.字符编码特征

我们主要对字符编码特征进行了探究:
字符编码特征是指将英文单词转换成数字序列的一种特征表示方式。在这种表示方式下,每个单词中的每个字符都被映射成一个数字。这种特征表示方式可以用于文本分类、情感分析、机器翻译等自然语言处理任务中。

字符编码特征有多种实现方式,下面介绍两种常用的方式:

One-Hot Encoding
One-Hot Encoding是将每个字符映射到一个唯一的数字上,然后将这个数字转化为一个长度为字符集大小的0/1向量。例如,如果我们考虑的字符集只包括26个英文字母,则每个字母可以映射到一个数字,如a映射到0,b映射到1,以此类推。然后我们将每个字符编码成一个长度为26的0/1向量,表示当前字符是否是对应位置的字母。例如,单词"cat"可以表示为[1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0]。

Word Embeddings
Word Embeddings是一种将单词映射到向量空间的技术。在这种表示方式下,每个单词都被映射到一个固定大小的向量上,这个向量包含了单词的语义信息。这个映射可以通过训练神经网络来完成,也可以使用预训练的词向量模型,如Word2Vec、GloVe等。与One-Hot Encoding相比,Word Embeddings可以更好地捕捉单词之间的语义关系,并且可以通过向量计算来实现单词的语义推理。

这些字符编码特征可以作为输入来训练神经网络,例如使用卷积神经网络、循环神经网络等进行文本分类、情感分析等自然语言处理任务。

2.3.word embedding

在Word Embeddings中,每个单词被映射到一个固定大小的向量上,这个向量包含了单词的语义信息。这个映射是通过训练神经网络来完成的,训练过程中神经网络通过观察大量的文本语料库来学习每个单词的上下文信息,并将这些上下文信息编码为一个向量表示。

具体来说,Word Embeddings中的每个向量维度都代表着某个语义特征,例如上下文中出现的单词、词性、情感极性等。这些维度的权重是通过神经网络自动学习得到的,因此可以更好地捕捉单词之间的语义关系。例如,在训练过程中,如果两个单词经常在相似的上下文中出现,那么它们对应的向量会比较接近。

这样,使用Word Embeddings的好处是可以将单词表示成实数向量,使得它们可以参与到神经网络的计算中,而不必考虑每个单词的具体编码方式。这种方式不仅节省了内存和计算资源,还能更好地反映单词的语义信息,从而提高了自然语言处理任务的性能。

2.4.用wordnet提取相似性的特征

这是一个模型,里面记录了每个单词的语义,可以用它来分析每个单词之间的相关性。
我的代码如下:

import nltk
from nltk.corpus import wordnet
import numpy as np

similarity=np.zeros((len(texts),1))
# 创建WordNet语料库的词汇关系工具
wn = nltk.corpus.wordnet
ind=0
for target_word in texts:
    word_list=texts
    # 为目标单词和每个单词计算相似度
    similarities = {}
    for word in word_list:
        target_synsets = wordnet.synsets(target_word)
        word_synsets = wordnet.synsets(word)
        scores = []
        for target_synset in target_synsets:
            for word_synset in word_synsets:
                score = target_synset.wup_similarity(word_synset)
                if score is not None:
                    scores.append(score)
        if len(scores) > 0:
            similarities[word] = np.sum(scores) / len(scores)
        else:
            similarities[word] = 0
    sumary = 0
    for key in similarities:
        sumary += similarities[key]
    avg = sumary / len(similarities)
    similarity[ind]=avg
np.savetxt('/kaggle/working/similarity.csv', similarity, delimiter=',')

2.5.查sentiwordnet语料库提取情感的特征

这个情感库是基于wordnet的,主要用于分析情绪

# 定义一个提取单个单词的情感分值的子函数
from nltk.corpus import wordnet as wn
from nltk.corpus import sentiwordnet as swn

def get_sentiment(word):
    synsets = list(swn.senti_synsets(word))
    pos_score = neg_score = obj_score = 0

    # 将每个词义的情感分值进行累加
    for syn in synsets:
        pos_score += syn.pos_score()
        neg_score += syn.neg_score()
        obj_score += syn.obj_score()

    # 将积极和消极得分输出
    return pos_score, neg_score,obj_score
在这里插入代码片

2.6.查阅wordnet语料库提取有几种词义

这是chatGPT给我生成的代码案例,wordnet更像是一种强大的神经网络字典,而且预训练好了,何乐而不为。

from nltk.corpus import wordnet
import nltk
nltk.download('wordnet')
word = 'dog'
synsets = wordnet.synsets(word)
num_senses = len(synsets)

print(f'The word "{word}" has {num_senses} senses.')

改进成批量:

# 输入单词数据
import csv
texts = []
with open('/kaggle/input/word-input/word_input.csv', newline='') as csvfile:
    reader = csv.reader(csvfile)
    for row in reader:
        texts.append(row[0])
import numpy as np
num_senses=np.zeros((len(texts),1))
ind=0
for word in texts:
    synsets = wordnet.synsets(word)
    num_senses[ind] = len(synsets)
    ind=ind+1
np.savetxt('/kaggle/working/ciyishu_output.csv', num_senses, delimiter=',')

三、难度分类

这里我已题目给的数据集中的每个单词每轮被猜中的概率作为特征,用k-means++进行聚类,分了四类下面是一张t-SNE降维后的散点图,可以发现轮廓比较均匀,并且输出每个簇的中心点,也是分的比较开的。
降维后的散点图
核心代码如下:

import pandas as pd
import numpy as np
from sklearn.cluster import KMeans,AffinityPropagation
from sklearn.metrics import silhouette_score
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt

# 读入数据
percentage_df = pd.read_csv('/kaggle/input/cluster-data/cluster_data.csv',index_col=0)


# 定义聚类数和KMeans模型
n_clusters = 4
kmeans = KMeans(n_clusters=n_clusters, init='k-means++')
# kmeans = AffinityPropagation(damping=0.5, max_iter=200, preference=None)

# 对数据进行聚类
kmeans.fit(percentage_df)

# 读入 CSV 数据文件
attribute_df = pd.read_csv('/kaggle/input/attribute/attribute_output.csv',index_col=0)

# 获取每一行的聚类结果并将其存储到DataFrame中
labels = kmeans.labels_
attribute_df = attribute_df.assign(label=labels)
clustered_data = percentage_df.assign(label=labels)
print(clustered_data)
# clustered_data['word'] = cluster_data['Word']
# 输出聚类结果
# 获取每个聚类的中心点
centroids = kmeans.cluster_centers_
print(centroids)
clustered_data.to_csv('clustered_data.csv', index=True)

# 输出标签数对应的饼状图
# 假设labels是你的聚类结果标签
labels=list(labels)
n_clusters = len(set(labels))

# 计算每个标签数目
sizes = [labels.count(i) for i in range(n_clusters)]

# 绘制饼图
plt.pie(sizes, labels=range(n_clusters), autopct='%1.1f%%', startangle=90)
plt.axis('equal')
plt.title('Cluster Distribution')
plt.legend(title='Cluster', loc='best')
plt.show()

在此之后,我们可以建立神经网络模型,下面是用keras库的源代码。

from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.utils import to_categorical
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt

# 假设训练数据存储在data中,其中最后一列为目标列
X = attribute_df.iloc[:, :10]  # 提取特征列
y = attribute_df['label']   # 提取目标列

# 对特征进行标准化处理
scaler = StandardScaler()
X = scaler.fit_transform(X)

# 将标记进行one-hot编码
y = to_categorical(y)

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.8, random_state=42)

# 初始化一个神经网络模型
model = Sequential()

# 添加输入层和隐藏层
model.add(Dense(128, activation='relu', input_dim=X.shape[1]))
model.add(Dense(64, activation='relu'))
model.add(Dense(32, activation='relu'))
# model.add(Dropout(0.1))
model.add(Dense(4, activation='softmax'))

# 添加输出层
model.add(Dense(4, activation='softmax'))

# 编译模型,指定损失函数、优化器和评估指标
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

# 训练模型
history=model.fit(X, y, batch_size=32, epochs=100, validation_split=0.2)

from keras.utils import to_categorical

# 使用模型进行测试集预测,得到分类结果
y_pred = model.predict(X_test)

# 将分类结果转化为one-hot向量
y_pred_one_hot = to_categorical(y_pred.argmax(axis=1), num_classes=4)

# 计算测试集准确率
accuracy = (y_pred_one_hot == y_test).mean()
print('Testing accuracy: %.2f' % accuracy)
# 绘制训练过程中的loss曲线
plt.plot(history.history['accuracy'], label='accuracy')
plt.plot(history.history['val_accuracy'], label='val_accuracy')
plt.legend()
plt.show()

最后我们验证集上的准确率也能达到


总结

简要写一下,等我考完雅思之后好好整理一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值