专栏首页程序生活中文问题相似度挑战赛baseline: lgb 0.84+

中文问题相似度挑战赛baseline: lgb 0.84+

1 赛事背景

问答系统中包括三个主要的部分:问题理解,信息检索和答案抽取。而问题理解是问答系统的第一部分也是非常关键的一部分。问题理解有非常广泛的应用,如重复评论识别、相似问题识别等。

重复问题检测是一个常见的文本挖掘任务,在很多实际问答社区都有相应的应用。重复问题检测可以方便进行问题的答案聚合,以及问题答案推荐,自动QA等。由于中文词语的多样性和灵活性,本赛题需要选手构建一个重复问题识别算法。

2 赛事任务

本次赛题希望参赛选手对两个问题完成相似度打分。

训练集:约5千条问题对和标签。若两个问题是相同的问题,标签为1;否则为0。

测试集:约5千条问题对,需要选手预测标签。

3 评审规则

1. 数据说明

训练集给定问题对和标签,使用\t进行分隔。测试集给定问题对,使用\t进行分隔。

eg:世界上什么东西最恐怖 世界上最恐怖的东西是什么? 1

解析:“世界上什么东西最恐怖”与”世界上最恐怖的东西是什么“问题相同,故是重复问题,标签为1。

2. 评估指标

本次竞赛的评价标准采用准确率指标,最高分为1。计算方法参考https://scikit-learn.org/stable/modules/generated/sklearn.metrics.accuracy_score.html,评估代码参考:

from sklearn.metrics import accuracy_score
y_pred = [0, 2, 1, 3]
y_true = [0, 1, 2, 3]
accuracy_score(y_true, y_pred)

4 特征工程

1 基础特征

# 文本长度特征
data['q1_len']=data['q1'].astype(str).map(len)
data['q2_len']=data['q2'].astype(str).map(len)
# 长度差特征:差/比例
data['q1q2_len_diff']=data['q1_len']-data['q2_len']
data['q1q2_len_diff_abs']=np.abs(data['q1_len']-data['q2_len'])
data['q1q2_rate']=data['q1_len']/data['q2_len']
data['q2q1_rate']=data['q2_len']/data['q1_len']
## 特殊符号特征
data['q1_end_special']=data['q1'].str.endswith('?').astype(int)
data['q2_end_special']=data['q2'].str.endswith('?').astype(int)

2 共现字特征

data['comm_q1q2char_nums']=data.apply(lambda  row:len(set(row['q1'])&set(row['q2'])),axis=1)
# 共现字位置
def char_match_pos(q1, q2, pos_i):
    q1 = list(q1)
    q2 = list(q2)

    if pos_i < len(q1):
        q2_len = min(len(q2), 25)  # q2_len只匹配前25个字
        for pos_j in range(q2_len):
            if q1[pos_i] == q2[pos_j]:
                q_pos = pos_j + 1  # 如果匹配上了 记录匹配的位置
                break
            elif pos_j == q2_len - 1:
                q_pos = 0  # 如果没有匹配上 赋值为0
    else:
        q_pos = -1  # 如果后续长度不存在 赋值为-1

    return q_pos


for pos_i in range(8):
    data['q1_pos_' + str(pos_i + 1)] = data.apply(
        lambda row: char_match_pos(row['q1'], row['q2'], pos_i), axis=1).astype(np.int8)

这里也可以用结巴分词,改成“词”粒度的

3 距离特征

print("===========距离特征 =============")
sim_func_dict = {"jaccard": distance.jaccard,
                 "sorensen": distance.sorensen,
                 "levenshtein": distance.levenshtein,
                 "ratio": Levenshtein.ratio
                 }

for sim_func in tqdm(sim_func_dict, desc="距离特征"):
    data[sim_func] = data.apply(lambda row: sim_func_dict[sim_func](row["q1"],row["q2"]), axis=1)
    qt = [[3, 3], [3, 5], [5, 5], [5, 10], [10, 10], [10, 15], [15, 15], [15, 25]]

    for qt_len in qt:
        if qt_len[0] == 3 and sim_func == "levenshtein":
            pass
        else:
            data[sim_func + '_q' + str(qt_len[0]) + '_t' + str(qt_len[1])] = data.apply(
                lambda row: sim_func_dict[sim_func](row["q1"][:qt_len[0]],
                                                    row["q2"][:qt_len[1]]),
                axis=1)

4 文本向量匹配特征

from scipy.spatial.distance import cosine, cityblock, canberra, euclidean, \
    minkowski, braycurtis, correlation, chebyshev, jensenshannon, mahalanobis, \
    seuclidean, sqeuclidean

from tqdm import tqdm

tqdm.pandas()

# 计算词向量的相似度
def get_w2v(query, title, num):
    q = np.zeros(100)
    count = 0
    for w in query:
        if w in w2v_model.wv:
            q += w2v_model.wv[w]
            count += 1
    if count == 0:
        query_vec = q
    query_vec = (q / count).tolist()

    t = np.zeros(100)
    count = 0
    for w in title:
        if w in w2v_model.wv:
            t += w2v_model.wv[w]
            count += 1
    if count == 0:
        title_vec = q
    title_vec = (t / count).tolist()

    if num == 1:
        try:
            vec_cosine = cosine(query_vec, title_vec)
            return vec_cosine
        except Exception as e:
            return 0
    if num == 2:
        try:
            vec_canberra = canberra(query_vec, title_vec) / len(query_vec)
            return vec_canberra
        except Exception as e:
            return 0
    if num == 3:
        try:
            vec_cityblock = cityblock(query_vec, title_vec) / len(query_vec)
            return vec_cityblock
        except Exception as e:
            return 0
    if num == 4:
        try:
            vec_euclidean = euclidean(query_vec, title_vec)
            return vec_euclidean
        except Exception as e:
            return 0
    if num == 5:
        try:
            vec_braycurtis = braycurtis(query_vec, title_vec)
            return vec_braycurtis
        except Exception as e:
            return 0
    if num == 6:
        try:
            vec_minkowski = minkowski(query_vec, title_vec)
            return vec_minkowski
        except Exception as e:
            return 0
    if num == 7:
        try:
            vec_correlation = correlation(query_vec, title_vec)
            return vec_correlation
        except Exception as e:
            return 0

    if num == 8:
        try:
            vec_chebyshev = chebyshev(query_vec, title_vec)
            return vec_chebyshev
        except Exception as e:
            return 0

    if num == 9:
        try:
            vec_jensenshannon = jensenshannon(query_vec, title_vec)
            return vec_jensenshannon
        except Exception as e:
            return 0

    if num == 10:
        try:
            vec_mahalanobis = mahalanobis(query_vec, title_vec)
            return vec_mahalanobis
        except Exception as e:
            return 0

    if num == 11:
        try:
            vec_seuclidean = seuclidean(query_vec, title_vec)
            return vec_seuclidean
        except Exception as e:
            return 0
    if num == 12:
        try:
            vec_sqeuclidean = sqeuclidean(query_vec, title_vec)
            return vec_sqeuclidean
        except Exception as e:
            return 0
# 词向量的相似度特征
data['vec_cosine'] = data.progress_apply(lambda index: get_w2v(index['q1_words_list'], index['q2_words_list'], 1),
                                         axis=1)
data['vec_canberra'] = data.progress_apply(
    lambda index: get_w2v(index['q1_words_list'], index['q2_words_list'], 2), axis=1)
data['vec_cityblock'] = data.progress_apply(
    lambda index: get_w2v(index['q1_words_list'], index['q2_words_list'], 3), axis=1)
data['vec_euclidean'] = data.progress_apply(
    lambda index: get_w2v(index['q1_words_list'], index['q2_words_list'], 4), axis=1)
data['vec_braycurtis'] = data.progress_apply(
    lambda index: get_w2v(index['q1_words_list'], index['q2_words_list'], 5), axis=1)
data['vec_minkowski'] = data.progress_apply(
    lambda index: get_w2v(index['q1_words_list'], index['q2_words_list'], 6), axis=1)
data['vec_correlation'] = data.progress_apply(
    lambda index: get_w2v(index['q1_words_list'], index['q2_words_list'], 7), axis=1)

data['vec_chebyshev'] = data.progress_apply(
    lambda index: get_w2v(index['q1_words_list'], index['q2_words_list'], 8), axis=1)
data['vec_jensenshannon'] = data.progress_apply(
    lambda index: get_w2v(index['q1_words_list'], index['q2_words_list'], 9), axis=1)
data['vec_mahalanobis'] = data.progress_apply(
    lambda index: get_w2v(index['q1_words_list'], index['q2_words_list'], 10), axis=1)
data['vec_seuclidean'] = data.progress_apply(
    lambda index: get_w2v(index['q1_words_list'], index['q2_words_list'], 11), axis=1)
data['vec_sqeuclidean'] = data.progress_apply(
    lambda index: get_w2v(index['q1_words_list'], index['q2_words_list'], 12), axis=1)

data['vec_cosine'] = data['vec_cosine'].astype('float32')
data['vec_canberra'] = data['vec_canberra'].astype('float32')
data['vec_cityblock'] = data['vec_cityblock'].astype('float32')
data['vec_euclidean'] = data['vec_euclidean'].astype('float32')
data['vec_braycurtis'] = data['vec_braycurtis'].astype('float32')
data['vec_correlation'] = data['vec_correlation'].astype('float32')

5 向量特征

def w2v_sent2vec(words):
    """计算句子的平均word2vec向量, sentences是一个句子, 句向量最后会归一化"""

    M = []
    for word in words:
        try:
            M.append(w2v_model.wv[word])
        except KeyError:  # 不在词典里
            continue

    M = np.array(M)
    v = M.sum(axis=0)
    return (v / np.sqrt((v ** 2).sum())).astype(np.float32).tolist()


fea_names = ['q1_vec_{}'.format(i) for i in range(100)]
data[fea_names] = data.progress_apply(lambda row: w2v_sent2vec(row['q1_words_list']), result_type='expand', axis=1)

fea_names = ['q2_vec_{}'.format(i) for i in range(100)]
data[fea_names] = data.progress_apply(lambda row: w2v_sent2vec(row['q2_words_list']), result_type='expand', axis=1)

5 模型训练

params = {
    'boosting_type': 'gbdt',
    'objective': 'binary',
    'num_leaves': 5,
    'max_depth': 6,
    'min_data_in_leaf': 450,
    'learning_rate': 0.1,
    'feature_fraction': 0.9,
    'bagging_fraction': 0.95,
    'bagging_freq': 5,
    'lambda_l1': 1,  
    'lambda_l2': 0.001,  # 越小l2正则程度越高
    'min_gain_to_split': 0.2,
}
 
oof = np.zeros(len(X))
prediction = np.zeros(len(X_test))
for fold_n, (train_index, valid_index) in enumerate(folds.split(X)):
    X_train, X_valid = X[features].iloc[train_index], X[features].iloc[valid_index]
    y_train, y_valid = y[train_index], y[valid_index]
    model = lgb.LGBMRegressor(**params, n_estimators=50000, n_jobs=-1)
    model.fit(X_train, y_train,
              eval_set=[(X_train, y_train), (X_valid, y_valid)],
              eval_metric='binary_logloss',
              verbose=50, early_stopping_rounds=200)
    y_pred_valid = model.predict(X_valid)
    y_pred = model.predict(X_test, num_iteration=model.best_iteration_)
    oof[valid_index] = y_pred_valid.reshape(-1, )
    prediction += y_pred
prediction /= n_fold

线下分数为

from sklearn.metrics import accuracy_score
y_pred = (oof > 0.5)
# score=accuracy_score(np.round(abs(oof)) ,train['label'].values)
score=accuracy_score(y_pred ,train['label'].values)

score

0.839,线上0.8406,线上和线下比较吻合

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 基于用户画像的商品推荐挑战赛Baseline【线上0.67】

    科大讯飞AI开发者大赛的比赛已经正式开幕了,这些赛题涉及了各个领域,包括CV、NLP以及传统的表格赛题等等,今天老肥和大家分享的是表格赛题-基于用户画像的商品推...

    老肥码码码
  • “梧桐杯”中国移动大数据应用创新大赛 - 智慧金融赛道Baseline

    老肥今天和大家分享的是“梧桐杯”中国移动大数据应用创新大赛的智慧金融赛道的Baseline方案(抱歉鸽了很久),线上成绩为0.9438,处于一个相对靠前的排名位...

    老肥码码码
  • 【人脸表情识别】情绪识别相关会议、比赛汇总(2018-2020)

    前面专栏中,我们介绍了有关基于图片/视频的人脸表情识别的相关内容,也了解了通过回归的方式来理解表情的方式——基于连续模型的人脸表情识别。在专栏的最后一篇文章中,...

    用户1508658
  • 2018腾讯广告算法大赛总结/0.772229/Rank11

    liupengsay/2018-Tencent-social-advertising-algorithm-contest​github.com

    Coggle数据科学
  • 鱼佬:百行代码入手数据挖掘赛!

    本实践以科大讯飞xDatawhale联合举办的数据挖掘赛为例,给出了百行代码Baseline,帮助学习者更好地结合赛事实践。同时,在如何提分上进行了详细解读,以...

    Datawhale
  • 交子杯 - 2020 - AI赛道 - TOP1

    陆陆续续两个月的赛程结束了,从初赛A榜27到B榜第4,再到决赛A,B双榜第一,有过断断续续排名下降即将无缘现场决赛的失落,也有过现场决赛等待被超越的12小时,心...

    zhangqibot
  • 基于LightGBM算法实现数据挖掘!

    本赛题是一个多分类的数据挖掘问题。赛题以医疗数据挖掘为背景,要求选手使用提供的心跳信号传感器数据训练模型并完成不同心跳信号的分类的任务。

    Datawhale
  • 零基础入门NLP - 新闻文本分类 方案整理

    比赛链接:https://tianchi.aliyun.com/forum/#raceId=531810 以下资料整理自比赛论坛,感谢这些无私开源的选手们,以...

    致Great
  • 你的广告能打几分?Kaggle需求预测挑战赛冠军方案这样做丨教程

    我们每天在网页上看到的各种电商广告,到底够不够吸引人?4个月前Kaggle和“俄罗斯版58同城”Avito办了个需求预测挑战赛,预测不同的广告能吸引用户多大的购...

    量子位
  • 2018科大讯飞AI营销算法大赛Baseline0.4255

    此baseline能达到0.42557的分数,分数一般,可以帮助快速进入到比赛。然后结合之前相关比赛的方法,能得到不错的分数。

    Coggle数据科学
  • 智慧支付挑战赛一等奖方案分享

    今天和大家分享的是前不久老肥我参加的银联商务和华东理工商学院一起举办的智慧支付挑战赛,本次比赛我也是单人参加,最终很高兴收获了一等奖的好成绩。

    老肥码码码
  • 10万元奖金,开启“智源粒子分类赛”下半时,三篇高分Baseline带你突破瓶颈!

    高能质子对撞中会产生大量粒子团喷注(jet),喷注可以根据其不同内在特性分为胶体喷注、轻夸克喷注、魅夸克喷注、美夸克喷注。

    大数据文摘
  • Mercari Price 比赛分享 —— 语言不仅是算法和公式而已

    最近半年一直在忙于各种NLP比赛,除夕因为kaggle的price写到凌晨3点,最后靠rp爬回季军,也算圆了一个solo gold的梦想。这应该是我2017下半...

    AI研习社
  • 项目实战01:“达观杯”文本竞赛

    》train_set.csv:此数据集用于训练模型,每一行对应一篇文章。文章分别在“字”和“词”的级别上做了脱敏处理。共有四列:

    用户5473628
  • 如何在算法比赛中获得出色的表现 :改善模型的5个重要技巧

    如果你最近才开始使用Kaggle,或者你是这个平台的老用户,你可能想知道如何轻松地提高你的模型的性能。以下是我在Kaggle之旅中积累的一些实用技巧。建立自己的...

    deephub
  • 迟来的面经,回馈牛客

    写个总结,回馈牛客~ 给自己也给未来面试的同学,少走弯路,命中率更高点~ 祝大家满意的offer多多(迟来的总结 [算法岗-机器学习方向]) 直接上干货 前期...

    牛客网
  • 刷新CoQA榜单记录:基于对抗训练和知识蒸馏的机器阅读理解方案解析

    一直以来,机器阅读理解都是自然语言处理界最受关注、进步最快的技术方向之一,主要有两大比赛较受瞩目,分别是注重一问一答的SQuAD [2]和多轮对话问答的CoQA...

    机器之心
  • 追一科技CoQA冠军方案分享:基于对抗训练和知识蒸馏的机器阅读理解方案

    近日,在由斯坦福大学发起的对话式问答挑战赛 CoQA (Conversational Question Answering Challenge)中,追一科技AI...

    AI研习社
  • 如何更快地将string转换成int/long

    在很多追求性能的程序挑战赛中,经常会遇到一个操作:将 String 转换成 Integer/Long。如果你没有开发过高并发的系统,或者没有参加过任何性能挑战赛...

    kirito-moe

扫码关注云+社区

领取腾讯云代金券