目录
任务1:数据集读取
-
1.1 简介
-
自然语言处理(Natural Language Processing, NLP)是计算机科学、人工智能和语言学的交叉领域,其目标是使计算机能够理解、生成和处理人类语言。常见的 NLP 技术包括语音识别、文本分析、机器翻译等。这些技术都是基于人工智能和机器学习的算法来实现的。
文本匹配是自然语言处理中的一种常见任务。它可以用来判断两个文本之间的相似度或相关性。常见的文本匹配任务包括:文本相似性匹配、问答匹配、查询-文档匹配等。这些任务的具体实现可以使用机器学习技术,例如使用神经网络模型进行文本嵌入,然后使用余弦相似度或其他相似度度量来计算文本之间的相似度。
LCQMC(Large-scale Chinese Question Matching Corpus)是一个大规模的中文文本匹配数据集。它包含超过 400,000 个标记为重复或非重复的问题对。该数据集由中国科学院自动化研究所(CASIA)深度学习技术与应用国家工程实验室(NEL-DLT)创建。
LCQMC 数据集中的问题涵盖广泛的主题,并以口语化的中文编写,使其成为文本匹配模型具有挑战性的数据集。该数据集通常用于训练和评估各种中文文本匹配模型的性能,例如基于神经网络的模型。它还用于中文自然语言处理的研究,例如文本匹配、文本分类和其他 NLP 任务。该数据集为研究人员提供了一个基准,用于评估其模型的性能并将其与最先进的方法进行比较。
-
1.2代码部分
-
#读取LCQMC数据集,为方便运行,将数据集保存在本地文件夹 data = pd.read_csv('LCQMC.test.data/LCQMC.test.data', sep='\t', names=['query1', 'query2', 'label']) #按照80%、10%、10%划分训练集、验证集和测试集 train = data[:10000] valid = data[10000:11250] test = data[11250:12500] #查看数据集 print("-------------------------数据集为-------------------------") print(data) #查看他们的形状 print('数据集',data.shape) print('测试集',train.shape) print('验证集',valid.shape) print('测试集',test.shape) #查看数据类型 print(type(data)) print(train)
-
任务1结束
任务2:文本数据分析
2.1任务介绍
- 步骤1:分析赛题文本长度,相似文本对与不相似文本对的文本长度是否存在差异?
- 步骤2:分析赛题单词和字符个数,在所有文本中包含多少个单词(用jieba进行分析)和字符?
在LCQMC数据集中数据采用三列进行存储,其中label为是否含义相同的标签。在任务2中我们希望各位同学,能对中文文本进出初步的分析,找到相似文本对和不相似文本对的差异。
query1 | query2 | label | |
---|---|---|---|
0 | 喜欢打篮球的男生喜欢什么样的女生 | 爱打篮球的男生喜欢什么样的女生 | 1 |
1 | 我手机丢了,我想换个手机 | 我想买个新手机,求推荐 | 1 |
2 | 大家觉得她好看吗 | 大家觉得跑男好看吗? | 0 |
jieba是一个中文分词库,用于将中文句子分解为词组。它使用了基于前缀词典的最大匹配算法,并支持用户自定义词典。要使用Jieba库,首先需要安装它。使用 pip 可以轻松安装:
pip install jieba
安装完成后,可以使用下面的代码对句子进行分词:
import jieba
sentence = "我在学习使用jieba分词"
seg_list = jieba.cut(sentence)
print(" ".join(seg_list))
输出结果是:我 在 学习 使用 jieba 分词。还可以使用jieba.lcut() or jieba.lcut_for_search() 获取词组列表。
2.2代码部分
将字符串长度和长度差写入data
#ql = query len,lc = length 差
data.insert(data.shape[1], 'ql1', 0)
data.insert(data.shape[1], 'ql2', 0)
data.insert(data.shape[1], 'lc', 0)
for i in range(len(data)):
data['ql1'][i] = len(data.query1[i])
data['ql2'][i] = len(data.query2[i])
data['lc'][i] = abs(len(data.query2[i]) - len(data.query1[i]))
将训练集按照标签划分两部分,将长度差计入程序 ,其中label为1的共5012个,label为4988个
label1 = train[train.label == 1]
label0 = train[train.label == 0]
print(label1)
print(label0)
#重新标号
label1.index = range(0,len(label1))
label0.index = range(0,len(label0))
print(label0)
print(label1)
#转化为列表
c1 = label1['lc'].values.tolist()
c0 = label0['lc'].values.tolist()
#print(c1)
#print(c0)
画图查看,开始查看整个训练集,发现数据过大,后筛选前一百个
fig = plt.figure()
ax1 = fig.add_subplot(1,2,1)
plt.plot(c1[:100],'g--')
ax2 = fig.add_subplot(1,2,2)
plt.plot(c0[:100],'k--')
#plt.show()
整体效果如下图所示:
发现看不出来什么区别,进行长度差统计,其中差别超过10的按10计算,差别从0到10,可得
虽然大致相同,但是随着差别越来越大,不相似的概率也越来越大。
对单词进行划分、计数,其代码为
#统计测试集中单词
CoSentence1 = train['query1'].drop_duplicates().values.tolist()
CoSentence2 = train['query2'].drop_duplicates().values.tolist()
CoSentence = CoSentence1 + CoSentence2
#print(CoSentense)
word2index = {}
word2count = {}
index2word = {}
n_words = 0
for pair in CoSentence:
seg_list = jieba.cut(pair)
for word in seg_list:
if word not in word2index:
word2index[word] = n_words
word2count[word] = 1
index2word[n_words] = word
n_words += 1
else:
word2count[word] += 1
print(n_words)
print(word2index)
print('------------------------------------')
print(word2count)
构建字典成果,将9102个词组计入字典中:
接着是其出现的频率:
- 任务2结束
任务3:文本相似度(统计特征)
3.1任务描述
- 步骤1:对query1和query2计算文本统计特征
- query1和query2文本长度
- query1和query2文本单词个数
- query1和query2文本单词差异
- query1和query2文本最长公用字符串长度
- query1和query2文本的TFIDF编码相似度
- 步骤2:根据相似度标签,上述哪一个特征最有区分性?
文本统计特征是指对文本进行统计并得到的一些数值,可以用来描述文本的特征。基础的文本特征包括:
文本长度: 文本中的字符数或单词数
字符频率: 每个字符在文本中出现的次数或频率
单词频率: 每个单词在文本中出现的次数或频率
句子长度: 文本中句子的平均长度
句子数量: 文本中句子的数量
上述文本特征都是无监督的,不局限语言和模型,而且计算快速,在任务3中我们需要大家使用python统计相似的文本和不相似文本的基础统计特征。
3.2代码部分
- query1和query2文本长度
ql1 = label1['ql1'].values.tolist()
ql2 = label0['ql2'].values.tolist()
#qln1:ql1的字符数统计
qln1 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
j = 0
for j in range(len(ql1)):
qln1[ql1[j]] = qln1[ql1[j]] + 1
print(qln1)
#qln2:ql2的字符数统计
qln2 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
k = 0
for k in range(len(ql2)):
qln2[ql2[k]] = qln2[ql2[k]] + 1
print(qln2)
在前文已将每个query的字符数统计出来保存在data中,因此第一步将其转化为列表,第二步对其字符数进行统计:
可以看出,两个query的字符数主要集中在6~15中,其余则随着数字的增加或者减少而减少,没有少于3个或者多于26个字符的。
- query1和query2文本单词个数
#查看query1和query2的单词个数
query1wordnumber = {}
query1wordcount = {}
query1word = {}
query1_n_words = 0
for pair1 in CoSentence1:
seg_list1 = jieba.cut(pair1)
for word1 in seg_list1:
if word1 not in query1wordnumber:
query1wordnumber[word1] = query1_n_words
query1wordcount[word1] = 1
query1word[n_words] = word1
query1_n_words += 1
else:
query1wordcount[word1] += 1
print('query1的单词数为:',query1_n_words)
query2wordnumber = {}
query2wordcount = {}
query2word = {}
query2_n_words = 0
for pair2 in CoSentence2:
seg_list2 = jieba.cut(pair2)
for word2 in seg_list2:
if word2 not in query2wordnumber:
query2wordnumber[word2] = query2_n_words
query2wordcount[word2] = 1
query2word[n_words] = word2
query2_n_words += 1
else:
query2wordcount[word2] += 1
print('query2的单词数为:',query2_n_words)
最终我们得到query1的单词数量和query2的单词数量,query2的词汇数量略多于query1。
query1_word = list(query1wordcount.keys())
query2_word = list(query2wordcount.keys())
q12gong = [wordgong for wordgong in query1_word if wordgong in query2_word]
q12butong = [wordcha for wordcha in (query1_word + query2_word) if wordcha not in q12gong]
print("相同的词有:")
print(q12gong)
print(len(q12gong))
print()
print()
print("不同的词有:")
print(q12butong)
print(len(q12butong))
相同的词共7130个
不同的词共1972个
- query1和query2文本最长公用字符串长度
def func(a, b):
if len(a) < len(b):
a, b = b, a
b_list_out = []
start_sign = 0
for i in range(1, len(b)+1):
c = b[start_sign:i]
if c in a:
b_list_out.append(len(c))
else:
start_sign = i - 1
b_list_out.sort()
if b_list_out:
return (b_list_out[-1])
else:
return (0)
strlong = []
print(len(CoSentence2))
print(len(CoSentence1))
for a in range(len(CoSentence2)):
strlong.append(func(CoSentence1[a],CoSentence2[a]))
print(strlong)
print(max(strlong),strlong.index(max(strlong)))
print(CoSentence2[7196],CoSentence1[7196])
print(len(CoSentence1[7196]))
将最长公用字符串长度进行计数,存储到列表之中,接着查看最长的所在的下标,发现最长的有17个字符串相同,而其总长为23/22
- query1和query2文本的TFIDF编码相似度
def TF_IDF(s1, s2):
s1_cut = [i for i in jieba.cut(s1, cut_all=True) if i != '']
s2_cut = [i for i in jieba.cut(s2, cut_all=True) if i != '']
word_set = set(s1_cut).union(set(s2_cut))
word_dict = dict()
i = 0
for word in word_set:
word_dict[word] = i
i += 1
s1_cut_code = [word_dict[word] for word in s1_cut]
s1_cut_code = [0] * len(word_dict)
for word in s1_cut:
s1_cut_code[word_dict[word]] += 1
s2_cut_code = [word_dict[word] for word in s2_cut]
s2_cut_code = [0] * len(word_dict)
for word in s2_cut:
s2_cut_code[word_dict[word]] += 1
# 计算余弦相似度
sum = 0
sq1 = 0
sq2 = 0
for i in range(len(s1_cut_code)):
sum += s1_cut_code[i] * s2_cut_code[i]
sq1 += pow(s1_cut_code[i], 2)
sq2 += pow(s2_cut_code[i], 2)
try:
result = round(float(sum) / (math.sqrt(sq1) * math.sqrt(sq2)), 2)
except ZeroDivisionError:
result = 0.0
return result
shujuTFIDF = []
for b in range(len(CoSentence1)):
shujuTFIDF.append(TF_IDF(CoSentence1[b],CoSentence2[b]))
len1 = 0
print(shujuTFIDF)
最终得到TF-IDF相似度:
其中数字越接近1则表示越相似,越接近0则表示越不相似。不难看出,TFIDF编码相似度最具有区分性。
- 任务3结束