Kaggle竞赛题:https://www.kaggle.com/c/home-depot-product-search-relevance
具体解法:https://blog.csdn.net/iam_emily/article/details/81067697
Step1:导入所需
df_train = pd.read_csv('../input/train.csv',encoding='ISO-8859-1')
df_test = pd.read_csv('../input/test.csv',encoding='ISO-8859-1')
df_desc = pd.read_csv('../input/product_descriptions.csv',encoding='ISO-8859-1')
df_all = pd.concat((df_train,df_test),axis=0,ignore_index=True)
print(df_all.shape)
df_all = pd.merge(df_all,df_desc,how='left',on='product_uid')
print(df_all.shape)
print(df_all.head())
我们这里遇到的文本预处理比较简单,因为最主要的就是看关键词是否会被包含。
所以我们统一化我们的文本内容,以达到任何term在我们的数据集中只有一种表达式的效果。
我们这里用简单的Stem做个例子:
(有兴趣的同学可以选用各种你觉得靠谱的预处理方式:去掉停止词,纠正拼写,去掉数字,去掉各种emoji,等等)
stemmer = SnowballStemmer('english')
def str_stemmer(s):
return ' '.join([stemmer.stem(word) for word in s.lower().split()])
df_all['search_term']=df_all['search_term'].map(lambda x:str_stemmer(x))
df_all['product_description']=df_all['product_description'].map(lambda x:str_stemmer(x))
df_all['product_title']=df_all['product_title'].map(lambda x:str_stemmer(x))
Step 3: 进阶版文本特征
Levenshtein
df_all['dist_term_title'] = df_all.apply(lambda x: leven.ratio(x['search_term'],x['product_title']),axis=1)
df_all['dist_term_desc'] = df_all.apply(lambda x:leven.ratio(x['search_term'],x['product_description']),axis=1)
TF-iDF
目标是生成一个字典
df_all['all_texts']=df_all['product_title'] + ' . ' + df_all['product_description'] + ' . '
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)
生成语料库
class MyCorpus(object):
def __iter__(self):
for x in df_all['all_texts'].values:
yield dictionary.doc2bow(list(tokenize(x,errors='ignore')))
corpus = MyCorpus()
使用TFIDF
from gensim.models.tfidfmodel import TfidfModel
tfidf = TfidfModel(corpus)
tfidf[dictionary.doc2bow(list(tokenize('hello world, good morning', errors='ignore')))]
计算矩阵相似度
from gensim.similarities import MatrixSimilarity
#先把刚刚那句话包装成一个方法
def to_tfidf(text):
res = tfidf[dictionary.doc2bow((list(tokenize(text,errors='ignore'))))]
return res
def cos_sim(text1,text2):
tfidf1 = to_tfidf(text1)
tfidf2 = to_tfidf(text2)
index = MatrixSimilarity([tfidf1],num_features=len(dictionary))
return float(index[tfidf2][0])
text1='hello world'
text2='hello from the other side'
cos_sim(text1,text2)
df_all['tfidf_cos_sim_in_title'] = df_all.apply(lambda x: cos_sim(x['search_term'], x['product_title']), axis=1)
df_all['tfidf_cos_sim_in_desc'] = df_all.apply(lambda x: cos_sim(x['search_term'], x['product_description']), axis=1)
word2vec
w2v和tfidf有个很大的不同。对于tfidf而言,只需要知道一整段text中包含了哪些word元素就行了。其他都不用care。
但是w2v要考虑到句子层级的split,以及语境前后的考虑。
所以,刚刚tfidf的corpus不能直接被这里使用。在这里,我们需要把句子/文字都给分类好。
这里,我们再玩儿一个NLP的杀器:NLTK。
import nltk
# nltk也是自带一个强大的句子分割器。
tokenizer = nltk.data.load('tokenizers/punkt/english.pickle')
from gensim.models.word2vec import Word2Vec
model = Word2Vec(w2v_corpus, size=128, window=5, min_count=5, workers=4)
最后建立模型