Kaggle - Home Depot Product Search Relevance 进阶篇

Github: https://github.com/yjfiejd/Product_search_relevance_NLP-/blob/master/product_search_relevance_advanced.ipynb (可查看jupyter notebook)
  • 基础篇与进阶篇最大的区别:特征提取的方式不同
  • 基础篇中特征的提取太粗糙:1)关键字常长度 2)用搜索词中的单词在产品title、产品介绍中出现的次数来衡量
  • 进阶篇的特征提取:采用了3中方法,在原有文本上共提取出了6个新的特征
  1. Levenshtein : 用来计算字符串之间的距离 -> 2个新特征 -> 搜索词句子与产品title,搜索词与产品描述直接的距离
  2. TF-idf构造特征: -> 2个新特征
    1. 新建all_text列(放入product_title+product_description,组合为一条句子)
    2. 把all_text列中每一个格子的句子拆分为单词(gensim.utils库中的Tokenize) -> 包含221877单词的大字典 -> 语料库用iterator实现,用class来实现
    3. 得到标准形式的语料库 TfidModel(corpus)
    4. 用MatrixSimilarity计算相似度,计算两条句子的相似度 -> 增加两个特征 -> 搜索词与产品title、搜索词与产品描述的相似度
  3. 通过Word2Vec来评判距离,搜索词与产品title,产品描述的 -> 2个新特征
    1. nltk也是自带一个强大的句子分割器。【调用工具】
    2. 我们先把长文本搞成list of 句子,再把句子变成list of 单词:【文本->句子】
    3. 我们把list of lists 给 flatten了。【句子 -> 扁平化flatten】
    4. 我们把句子里的单词给分好。可以用刚刚Gensim的tokenizer, 也可以用nltk的word_tokenizer 【句子 -> 单词】
    5. 训练我们的预料库,成为词向量 【单词 -> 训练语料库model】
    6. 可以得到每个单词的向量,但是每一格句子中由多个单词组成,把每个单词向量取平均,
    7. 计算两个句子的vector的相似度, 用cosine similarity,用scipy的spatial功能
    8. 应用在两列上, 得到新的2个特征:df_all.apply(lambda x: w2v_cos_sim(x['search_term'], x['product_title']), axis=1)
    9. 去掉不需要的column,给drop掉, 留下新特征

代码如下:

# -*- coding:utf8 -*-
# @TIME : 2018/4/27 上午6:15
# @Author : Allen
# @File : product_search_relevance_advanced.py

#目的:给出输入关键字与搜索结果,评价搜索准确度
#读取数据
df_train = pd.read_csv('train.csv', encoding = "ISO-8859-1")
df_test = pd.read_csv('test.csv', encoding = "ISO-8859-1")
df_desc = pd.read_csv('product_descriptions.csv')
#处理思路
#1,导入包、数据  -> 合并数据格式concat,merge,
#2,文本预处理 -> 【简单方法】:看输入词是在搜索结果中出现几次,需要先统一数据集格式 -> str_stemmer and str_commond_words 处理数据
#3,自制文本特征 -> 关键词长度/搜索词语与title和describtion中重复词语数 -> 去掉之前的英文,保留自制特征
#4,重塑训练/测试集 -> 拆分出X_train, X_test, y_train, 去除label
#5,建立模型:Ridge回归模型RandomForestRegressor 找出最佳参数max_depth=7 通过多种参数导入 -> 画图
#6,上传结果:生成csv文件
#########1) 导入需要用的库
import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier, BaggingRegressor
from nltk.stem.snowball import SnowballStemmer
import os
# 解决路径报错问题:SyntaxError: (unicode error) 'unicodeescape':https://www.cnblogs.com/renfanzi/p/6307074.html
f = r'C:\Users\xiaochen.liu\Desktop\product_search_relevance'
os.chdir(f)
#读取数据
df_train = pd.read_csv('train.csv', encoding = "ISO-8859-1")
df_test = pd.read_csv('test.csv', encoding = "ISO-8859-1")
df_desc = pd.read_csv('product_descriptions.csv')
#合并测试集与训练集,便于统一文本预处理
#PANDAS 数据合并与重塑(concat篇):https://blog.csdn.net/stevenkwong/article/details/52528616
#PANDAS 数据合并与重塑(join/merge篇):https://blog.csdn.net/stevenkwong/article/details/52540605
df_all = pd.concat((df_train, df_test), axis=0, ignore_index=True)
df_all.head()
#print(df_all.shape)
#把描述信息加入表,how='left'表示左边全部保留,on表示以什么为基准对齐
df_all = pd.merge(df_all, df_desc, how='left', on='product_uid')
df_all.head()
#############2) 文本预处理,把表格的语句处理为计算机能懂的格式,这里使用NLTK
stemmer = SnowballStemmer('english')
#把每一列中的每一条产品说明中的英文句子,小写lower() -> 分割split() -> 提取词干stemmer.stem -> 整合join
def str_stemmer(s):
    return " ".join([stemmer.stem(word) for word in s.lower().split()])
#计算"关键词次数" : 统计两个字符串中的相同单词的个数
#python find()方法:http://www.runoob.com/python/att-string-find.html
def str_common_word(str1, str2):
    return sum(int(str2.find(word)>=0) for word in str1.split())
#把每一个column都跑一遍,用str_stemmer清洁所有的文本内容
#这3行我跑了10几分钟 - 为渣渣电脑默哀一分钟
df_all['search_term'] = df_all['search_term'].map(lambda x: str_stemmer(x))
df_all['product_title'] = df_all['product_title'].map(lambda x: str_stemmer(x))
df_all['product_description'] = df_all['product_description'].map(lambda x: str_stemmer(x))
##############3) 【区别】进阶版文本特征
# 新特征介绍:Levenshtein 计算两个字符串单词的距离
import Levenshtein
Levenshtein.ratio('hello', 'hello world')
#【新特征1】: search_term 和 product_title比较
df_all['dist_in_title'] = df_all.apply(lambda x:Levenshtein.ratio(x['search_term'],x['product_title']), axis=1)
#【新特征2】: search_term 和 product_description比较
df_all['dist_in_desc'] = df_all.apply(lambda x:Levenshtein.ratio(x['search_term'],x['product_description']), axis=1)
#【新特征3】: 采用TF-iDF构造新的特征: -> 【这里新增了2个特征】
#1)新建all_text列(放入product_title+product_description,组合为一条句子)
#2)把all_text列中每一个格子的句子拆分为单词(gensim.utils库中的Tokenize) -> 包含221877单词的大字典 -> 语料库用iterator实现,用class来实现
#3)得到标准形式的语料库 TfidModel(corpus),
#4) 用MatrixSimilarity计算相似度,计算两条句子的相似度 -> 增加两个特征 -> 搜索词与产品title、搜索词与产品描述的相似度


#把训练集,先fit里面的文本信息,然后在来transform转换成TIIDF的格式  
#X_train = feature_extraction.fit_transform(train["combined_news"].values)  
#这里因为feature_extraction记住了训练的格式,转换测试集的格式  
#X_test = feature_extraction.transform(test["combined_news"].values)  
#y_train = train["Label"].values  
#y_test = test["Label"].values  

#新建一列,保存为所有的文本除了search term, 加上句号
df_all['all_texts'] = df_all['product_title'] + ' . ' + df_all['product_description'] + ' . '
#打印看一下效果
df_all['all_texts'][:5]
# 有了组合好的句子,可以分词了准备
# 分词:这里我们用gensim,为了更加细致的分解TFIDF的步骤动作;其实sklearn本身也有简单好用的tfidf模型
# Tokenize可以用各家或者各种方法,就是把长长的string变成list of tokens。包括NLTK,SKLEARN都有自家的解决方案

from gensim.utils import tokenize
from gensim.corpora.dictionary import Dictionary
#得到了一个很多单词的大词典
dictionary = Dictionary(list(tokenize(x, errors='ignore')) for x in df_all['all_texts'].values)
print(dictionary)
#这个类所做的事情也很简单,就是扫便我们所有的语料,并且转化成简单的单词的个数计算
class MyCorpus(object):
    def __iter__(self):
        for x in df_all['all_texts'].values:
            yield dictionary.doc2bow(list(tokenize(x, errors='ignore')))

# 这里这么折腾一下,仅仅是为了内存friendly。面对大量corpus数据时,你直接存成一个list,会使得整个运行变得很慢。
# 所以我们搞成这样,一次只输出一组。但本质上依旧长得跟 [['sentence', '1'], ['sentence', '2'], ...]一样
corpus = MyCorpus()
#有了我们标准形式的语料库,我们于是就可以init我们的TFIDFmodel了。这里做的事情,就是把已经变成BoW向量的数组,做一次TFIDF的计算。
from gensim.models.tfidfmodel import TfidfModel
tfidf = TfidfModel(corpus)
#示例:这下我们看看一个普通的句子放过来长什么样子:
tfidf[dictionary.doc2bow(list(tokenize('hello world, good morning', errors='ignore')))]
#怎么判断两个句子的相似度呢?
#这里有个trick,因为我们得到的tfidf只是『有这个字,就有这个值』,并不是一个全部值。
#也就是说,两个matrix可能size是完全不一样的。
#想用cosine计算的同学就会问了,两个matrix的size都不fix,怎么办?
#咦,这里就注意咯。他们的size其实是一样的。只是把全部是0的那部分给省略了对吧?
#于是,我们只要拿其中一个作为index。扩展开全部的matrixsize,另一个带入,就可以计算了

from gensim.similarities import MatrixSimilarity

# 先把刚刚那句话包装成一个方法
def to_tfidf(text):
    res = tfidf[dictionary.doc2bow(list(tokenize(text, errors='ignore')))]
    return res

# 然后,我们创造一个cosine similarity的比较方法
def cos_sim(text1, text2):
    tfidf1 = to_tfidf(text1)
    tfidf2 = to_tfidf(text2)
    index = MatrixSimilarity([tfidf1],num_features=len(dictionary))
    sim = index[tfidf2]
    # 本来sim输出是一个array,我们不需要一个array来表示,
    # 所以我们直接cast成一个float
    return float(sim[0])
#举例说明
text1 = 'hello world'
text2 = 'hello from the other side'
cos_sim(text1, text2)
#计算搜索词语与产品title相似度
df_all['tfidf_cos_sim_in_title'] = df_all.apply(lambda x: cos_sim(x['search_term'], x['product_title']), axis=1)
#计算搜索词与产品描述description相似度
df_all['tfidf_cos_sim_in_desc'] = df_all.apply(lambda x: cos_sim(x['search_term'], x['product_description']), axis=1)
#【新特征4】:通过Word2Vec来评判距离,搜索词与产品title,产品描述的。

import nltk
#1)nltk也是自带一个强大的句子分割器。【调用工具】
tokenizer = nltk.data.load('tokenizers/punkt/english.pickle')
#2)我们先把长文本搞成list of 句子,再把句子变成list of 单词:【文本->句子】
sentences = [tokenizer.tokenize(x) for x in df_all['all_texts'].values]
#3)我们把list of lists 给 flatten了。【句子 -> 扁平化flatten】
sentences = [y for x in sentences for y in x] #一共1998321个句子。
#4)我们把句子里的单词给分好。可以用刚刚Gensim的tokenizer, 也可以用nltk的word_tokenizer 【句子 -> 单词】
from nltk.tokenize import word_tokenize
w2v_corpus = [word_tokenize(x) for x in sentences]
#5) 训练我们的预料库,成为词向量 【单词 -> 训练语料库model】
from gensim.models.word2vec import Word2Vec
model = Word2Vec(w2v_corpus, size=128, window=5, min_count=5, workers=4)

#6) 可以得到每个单词的向量,但是每一格句子中由多个单词组成,把每个单词向量取平均,
vocab = model.vocab
#得到任意text句子的vector(就是取平均)
def get_vector(text):
    reso = np.zeros([128])
    count = 0
    for word in word_tokenize(text):
        res += model[word]
        count+=1
    return res/count
#测试一下,每条句子的vector:
print(get_vector('life is like a box of chocolate'))
#7) 计算两个句子的vector的相似度, 用cosine similarity,用scipy的spatial功能
from scipy import spatial
def w2v_cos_sim(text1, text2):
    try:
        w2v1 = get_vector(text1)
        w2v2 = get_vector(text2)
        sim = 1 - spatial.distance.cosine(w2v1, w2v2)
#9) 去掉不需要的column,给drop掉
df_all = df_all.drop(['search_term','product_title','product_description','all_texts'],axis=1)

return float(sim) except: return float(0)#测试一下两个句子之间的距离w2v_cos_sim('hello world', 'hello from the other side')
#8) 应用在两列上, 得到新的2个特征
df_all['w2v_cos_sim_in_title'] = df_all.apply(lambda x: w2v_cos_sim(x['search_term'], x['product_title']), axis=1)
df_all['w2v_cos_sim_in_desc'] = df_all.apply(lambda x: w2v_cos_sim(x['search_term'], x['product_description']), axis=1)

*************************后面部分与基础篇一样**************************

################4) 把之前合并起来处理的训练集,测试集拿出来
#分离训练集合,测试集合
df_train = df_all.loc[df_train.index]
df_test = df_all.loc[df_test.index]
#记录测试ID
test_ids = df_test['id']
#分离出y_train
y_train = df_train['relevance'].values
#删除原集label
X_train = df_train.drop(['id', 'relevance'], axis=1).values
X_test = df_test.drop(['id', 'relevance'], axis = 1).values
################5) 建立模型 : RF
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import cross_val_score

#循环测试不同的树的深度
params = [1,3,5,6,7,8,9,10]
test_scores = []
for param in params:
    clf = RandomForestRegressor(n_estimators=30, max_depth=param)
    test_score = np.sqrt(-cross_val_score(clf, X_train, y_train, cv=5, scoring='neg_mean_squared_error'))
    test_scores.append(np.mean(test_score))
#画图
import matplotlib.pyplot as plt
%matplotlib inline
plt.plot(params, test_scores)
plt.title("Param vs CV Error");

#这里会得到一个最佳的树深度
################6) 上传结果
rf = RandomForestRegressor(n_estimators=30, max_depth=6)
rf.fit(X_train, y_train)
y_pred = rf.predict(X_test)
pd.DataFrame({"id": test_ids, "relevance": y_pred}).to_csv('submission.csv',index=False)






















  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是使用Python和Keras库来解决Kaggle Digit Recognizer比赛的代码示例: 首先,导入必要的库: ```python import pandas as pd import numpy as np from keras.models import Sequential from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPool2D from keras.optimizers import RMSprop from keras.preprocessing.image import ImageDataGenerator from sklearn.model_selection import train_test_split ``` 然后,读取和处理训练数据和测试数据: ```python train_data = pd.read_csv('train.csv') test_data = pd.read_csv('test.csv') # 将数据分成输入和输出 X_train = train_data.drop(['label'], axis=1) y_train = train_data['label'] # 将输入数据重塑为28x28像素 X_train = X_train.values.reshape(-1, 28, 28, 1) test_data = test_data.values.reshape(-1, 28, 28, 1) # 将像素值转换为浮点数并归一化 X_train = X_train.astype('float32') / 255 test_data = test_data.astype('float32') / 255 # 将输出数据转换为独热编码 y_train = pd.get_dummies(y_train).values ``` 接着,将数据分成训练集和验证集,设置数据增强器并构建卷积神经网络模型: ```python # 将数据分成训练集和验证集 X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.1) # 设置数据增强器 datagen = ImageDataGenerator( rotation_range=10, zoom_range = 0.1, width_shift_range=0.1, height_shift_range=0.1) # 构建卷积神经网络模型 model = Sequential() model.add(Conv2D(filters=32, kernel_size=(5,5), padding='Same', activation='relu', input_shape=(28,28,1))) model.add(Conv2D(filters=32, kernel_size=(5,5), padding='Same', activation='relu')) model.add(MaxPool2D(pool_size=(2,2))) model.add(Dropout(0.25)) model.add(Conv2D(filters=64, kernel_size=(3,3), padding='Same', activation='relu')) model.add(Conv2D(filters=64, kernel_size=(3,3), padding='Same', activation='relu')) model.add(MaxPool2D(pool_size=(2,2), strides=(2,2))) model.add(Dropout(0.25)) model.add(Flatten()) model.add(Dense(256, activation="relu")) model.add(Dropout(0.5)) model.add(Dense(10, activation="softmax")) # 定义优化器和损失函数 optimizer = RMSprop(lr=0.001, rho=0.9, epsilon=1e-08, decay=0.0) model.compile(optimizer=optimizer, loss="categorical_crossentropy", metrics=["accuracy"]) ``` 最后,使用训练集和验证集来训练和评估模型,并对测试数据进行预测: ```python # 训练模型 history = model.fit_generator(datagen.flow(X_train, y_train, batch_size=64), epochs=30, validation_data=(X_val, y_val), verbose=2) # 在验证集上评估模型 score = model.evaluate(X_val, y_val, verbose=0) print("Validation loss:", score[0]) print("Validation accuracy:", score[1]) # 对测试数据进行预测 predictions = model.predict(test_data) ``` 这就是一个简单的使用卷积神经网络和数据增强器来解决Kaggle Digit Recognizer比赛的代码示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值