Raki的NLP竞赛topline解读:NBME - Score Clinical Patient Notes

2023-11-13

Description

当你去看医生时,他们如何解释你的症状可以决定你的诊断是否准确。当他们获得执照时,医生们已经有了很多写病人笔记的练习,这些笔记记录了病人的主诉历史、体检结果、可能的诊断和后续护理。学习和评估写病人笔记的技能需要其他医生的反馈,这是一个时间密集的过程,可以通过加入机器学习来改进。

直到最近,第二步临床技能考试是美国医学执照考试®(USMLE®)的一个组成部分。该考试要求应试者与标准化病人(受过训练的人,以描绘特定的临床病例)互动,并写下病人的笔记。训练有素的医生评分员随后用概述每个病例的重要概念(被称为特征)的评分标准对病人笔记进行评分。在病历中发现的这种特征越多,分数就越高(除其他因素外,还包括对考试的最终得分的贡献)。

然而,让医生为病人笔记考试打分需要大量的时间,以及人力和财力资源。使用自然语言处理的方法已经被创造出来以解决这个问题,但病人笔记在计算上的评分仍然具有挑战性,因为特征可能以许多方式表达。例如,"对活动失去兴趣 "这一特征可以被表达为 “不再打网球”。其他挑战包括需要通过结合多个文本片段来映射概念,或出现模糊的否定词的情况,如 “没有不耐寒、脱发、心悸或震颤”,对应于关键的基本要素 “缺乏其他甲状腺症状”。

在这次比赛中,你将确定病人笔记中的具体临床概念。具体来说,你要开发一种自动方法,将考试评分标准中的临床概念(如 “食欲减退”)与医学生写的临床病人笔记中表达这些概念的各种方式(如 “吃得少”、“衣服更宽松”)进行映射。好的解决方案将既准确又可靠

Evaluation

比赛通过微观平均的F1分数来评估

对于每个实例,我们预测一组字符跨度。一个字符跨度是一对索引,代表文本中的一个字符范围。一个跨度i j代表索引为i到j的字符,左闭右开,在Python的符号中,一个跨度i j相当于一个切片 i:j

对于每个实例,都有一个基础真实跨度的集合和一个预测跨度的集合。我们用分号来划分跨度,比如。0 3; 5 9.

在这里插入图片描述

Data Description

这里介绍的文本数据来自USMLE® Step 2临床技能考试,这是一项医学执照考试。该考试衡量受训者在与标准化病人接触时识别相关临床事实的能力。

在这个考试中,每个应试者都会看到一个标准化病人,一个被训练来描述一个临床病例的人。在与病人交流后,应试者在一份病人笔记中记录下与之相关的事实。每份病人笔记都由受过训练的医生打分,医生会根据评分标准寻找与该病例相关的某些关键概念或特征。本次竞赛的目标是开发一种自动识别每份病人笔记中相关特征的方法,特别关注笔记中记录了与标准化病人面谈的信息的病史部分

Important Terms

  • 临床病例:标准化病人向应试者(医科学生、住院医师或医生)展示的情景(如症状、投诉、关切)。本数据集中有十个临床病例
  • 患者备注:详细说明患者在就诊期间(体检和问诊)的重要信息的文字
  • 特征:一个与临床相关的概念。一个评分标准描述了与每个病例相关的关键概念

Training Data

patient_notes.csv - 约40,000份病人笔记历史部分的集合。其中只有一个子集有特征注释。你可能希望在没有注释的笔记上应用无监督学习技术。测试集中的病人笔记不包括在该文件的公开版本中

  • pn_num - 每个病人笔记的唯一标识符
  • case_num - 一个病人笔记所代表的临床病例的唯一标识符
  • pn_history - 测试者所记录的经历的文本
    在这里插入图片描述

features.csv - 每个临床病例的特征(或关键概念)的评分标准。

  • feature_num - 每个特征的唯一标识符
  • case_num - 每个病例的唯一标识符
  • feature_text - 对特征的描述
    在这里插入图片描述
    train.csv - 1000份病人笔记的特征注释,10个病例中每个100份。
  • id - 每个病人笔记/特征对的唯一标识符
  • pn_num - 本行中注释的病人笔记
  • feature_num - 本行注释的特征
  • case_num - 该患者笔记所属的病例
  • annotation - 患者笔记中表示特征的文字。一个特征可以在一个笔记中被多次指出。
  • location - 表示每个注释在笔记中的位置的字符span。可能需要多个span来表示一个注释,在这种情况下,跨度由分号;分隔
    在这里插入图片描述

Example Test Data

为了帮助你编写提交的代码,我们包括一些从训练集中选出的实例。当你提交的笔记本被打分时,这个例子数据将被实际的测试数据所取代。测试集中的病人笔记将被添加到patient_notes.csv文件中。这些病人笔记与训练集中的病人笔记来自相同的临床病例。在测试集中大约有2000份病人笔记

  • test.csv - 从训练集中选择的实例
  • sample_submission.csv - 正确格式的提交样本文件
    在这里插入图片描述

赛题与数据集理解

首先要理解,这个任务不需要判断span所属的类别,仅需要判断所有span的位置即可

patient_notes这个包含各个病人病情的描述

然后我们要做的就是从病情描述里面抽取一些span,并识别它属于哪一种疾病,注意这个span是char级别的span,而不是token级别

DeBERTa

DeBERTa的主要改进在于使用了disentangled attention mechanism和enhanced mask decoder来增强BERT的表达能力

Raki的读paper小记:DEBERTA: DECODING-ENHANCED BERT WITH DISENTANGLED ATTENTION

Deberta-v3-large

RoBERTa

论文:《RoBERTa:A Robustly Optimized BERT Pretraining Approach》

作者/机构:Facebook + 华盛顿大学

论文地址:https://arxiv.org/pdf/1907.11692

年份:2019.7

RoBERTa在训练方法上对Bert进行改进,主要体现在改变mask的方式、丢弃NSP任务、训练超参数优化和使用更大规模的训练数据四个方面。其改进点如下:

静态Mask变动态Mask

Bert在整个预训练过程,选择进行mask的15%的Tokens是不变的,也就是说从一开始随机选择了这15%的Tokens,之后的N个epoch里都不再改变了。这就叫做静态Masking。

而RoBERTa一开始把预训练的数据复制10份,每一份都随机选择15%的Tokens进行Masking,也就是说,同样的一句话有10种不同的mask方式。然后每份数据都训练N/10个epoch。这就相当于在这N个epoch的训练中,每个序列的被mask的tokens是会变化的。这就叫做动态Masking。

这样做的目的是:动态mask相当于间接的增加了训练数据,有助于提高模型性能。

移去NSP任务

Bert为了捕捉句子之间的关系,使用了NSP任务进行预训练,就是输入一对句子A和B,判断这两个句子是否是连续的。两句子最大长度之和为512。

RoBERTa去除了NSP,而是每次输入连续的多个句子,直到最大长度512(可以跨文章)。这种训练方式叫做(FULL-SENTENCES),而原来的Bert每次只输入两个句子。

这样做的目的是:实验发现,消除NSP损失在下游任务的性能上能够与原始BERT持平或略有提高。这可能是由于Bert一单句子为单位输入,模型无法学习到词之间的远程依赖关系,而RoBERTa输入为连续的多个句子,模型更能俘获更长的依赖关系,这对长序列的下游任务比较友好。

更大的mini-batch

BERTbase 的batch size是256,训练1M个steps。RoBERTa的batch size是8k。

这样做的目的是:作者是借鉴了在了机器翻译中的训练策略,用更大的batch size配合更大学习率能提升模型优化速率和模型性能的现象,并且也用实验证明了确实Bert还能用更大的batch size。

更多的训练数据,更长的训练时间

借鉴RoBERTa(160G)用了比Bert(16G)多10倍的数据。性能确实再次彪升。当然,也需要配合更长时间的训练。

这样做的目的是:很明显更多的训练数据增加了数据的多样性(词汇量、句法结构、语法结构等等),当然能提高模型性能。

Roberta Strikes Back !

Initialization

import

import os 	#Python的模块
import re 	#正则表达式
import ast	#指的是Abstract Syntax Tree,抽象语法树	
import json	#处理json格式文件
import glob #glob模块用来查找文件目录和文件,并将搜索的到的结果返回到一个列表中
import numpy as np
import pandas as pd
from tqdm.notebook import tqdm

os.environ["TOKENIZERS_PARALLELISM"] = "false"

Paths

pytorch如何设置batch-size和num_workers,避免超显存, 并提高实验速度?
pytorch dataloader 使用batch和 num_works参数的原理是什么?

DATA_PATH = "../input/nbme-score-clinical-patient-notes/"
OUT_PATH = "../input/nbme-roberta-large/"
WEIGHTS_FOLDER = "../input/nbme-roberta-large/"

NUM_WORKERS = 2

Data

Preparation

用正则表达式对文本进行清洗

def process_feature_text(text): #利用正则表达式替换一些表示
    text = re.sub('I-year', '1-year', text) 
    text = re.sub('-OR-', " or ", text)
    text = re.sub('-', ' ', text)
    return text


def clean_spaces(txt): #替换掉文本中的各种形式空格
    txt = re.sub('\n', ' ', txt)
    txt = re.sub('\t', ' ', txt)
    txt = re.sub('\r', ' ', txt)
#     txt = re.sub(r'\s+', ' ', txt)
    return txt


def load_and_prepare_test(root=""):
    patient_notes = pd.read_csv(root + "patient_notes.csv")
    features = pd.read_csv(root + "features.csv")
    df = pd.read_csv(root + "test.csv")

    df = df.merge(features, how="left", on=["case_num", "feature_num"]) #合并,左连接
    df = df.merge(patient_notes, how="left", on=['case_num', 'pn_num'])

    df['pn_history'] = df['pn_history'].apply(lambda x: x.strip()) #去除文本首尾的空格
    df['feature_text'] = df['feature_text'].apply(process_feature_text)

    df['feature_text'] = df['feature_text'].apply(clean_spaces)
    df['clean_text'] = df['pn_history'].apply(clean_spaces)

    df['target'] = ""
    return df

Processing

import itertools


def token_pred_to_char_pred(token_pred, offsets): #将token级别的预测span转化为char span
    char_pred = np.zeros((np.max(offsets), token_pred.shape[1]))
    for i in range(len(token_pred)):
        s, e = int(offsets[i][0]), int(offsets[i][1])  # start, end
        char_pred[s:e] = token_pred[i]

        if token_pred.shape[1] == 3:  # following characters cannot be tagged as start
            s += 1
            char_pred[s: e, 1], char_pred[s: e, 2] = (
                np.max(char_pred[s: e, 1:], 1),
                np.min(char_pred[s: e, 1:], 1),
            )

    return char_pred


def labels_to_sub(labels): #标签到下标
    all_spans = []
    for label in labels:
        indices = np.where(label > 0)[0]
        indices_grouped = [
            list(g) for _, g in itertools.groupby(
                indices, key=lambda n, c=itertools.count(): n - next(c)
            )
        ]

        spans = [f"{min(r)} {max(r) + 1}" for r in indices_grouped]
        all_spans.append(";".join(spans))
    return all_spans


def char_target_to_span(char_target): #拿到预测的char,返回span
    spans = []
    start, end = 0, 0
    for i in range(len(char_target)):
        if char_target[i] == 1 and char_target[i - 1] == 0:
            if end:
                spans.append([start, end])
            start = i
            end = i + 1
        elif char_target[i] == 1:
            end = i + 1
        else:
            if end:
                spans.append([start, end])
            start, end = 0, 0
    return spans

Tokenization

分词器

import numpy as np
from transformers import AutoTokenizer


def get_tokenizer(name, precompute=False, df=None, folder=None):
    if folder is None: #如果没有预训练好的分词器就根据模型名称加载一个
        tokenizer = AutoTokenizer.from_pretrained(name)
    else:
        tokenizer = AutoTokenizer.from_pretrained(folder)

    tokenizer.name = name
    tokenizer.special_tokens = {
        "sep": tokenizer.sep_token_id,
        "cls": tokenizer.cls_token_id,
        "pad": tokenizer.pad_token_id,
    }

    if precompute:
        tokenizer.precomputed = precompute_tokens(df, tokenizer)
    else:
        tokenizer.precomputed = None

    return tokenizer


def precompute_tokens(df, tokenizer):
    feature_texts = df["feature_text"].unique()

    ids = {}
    offsets = {}

    for feature_text in feature_texts:
        encoding = tokenizer(
            feature_text,
            return_token_type_ids=True,
            return_offsets_mapping=True,
            return_attention_mask=False,
            add_special_tokens=False,
        )
        ids[feature_text] = encoding["input_ids"]
        offsets[feature_text] = encoding["offset_mapping"]

    texts = df["clean_text"].unique()

    for text in texts:
        encoding = tokenizer(
            text,
            return_token_type_ids=True,
            return_offsets_mapping=True,
            return_attention_mask=False,
            add_special_tokens=False,
        )
        ids[text] = encoding["input_ids"]
        offsets[text] = encoding["offset_mapping"]

    return {"ids": ids, "offsets": offsets}


def encodings_from_precomputed(feature_text, text, precomputed, tokenizer, max_len=300):
    tokens = tokenizer.special_tokens

    # Input ids
    if "roberta" in tokenizer.name:
        qa_sep = [tokens["sep"], tokens["sep"]]
    else:
        qa_sep = [tokens["sep"]]

    input_ids = [tokens["cls"]] + precomputed["ids"][feature_text] + qa_sep
    n_question_tokens = len(input_ids)

    input_ids += precomputed["ids"][text]
    input_ids = input_ids[: max_len - 1] + [tokens["sep"]]

    # Token type ids
    if "roberta" not in tokenizer.name:
        token_type_ids = np.ones(len(input_ids))
        token_type_ids[:n_question_tokens] = 0
        token_type_ids = token_type_ids.tolist()
    else:
        token_type_ids = [0] * len(input_ids)

    # Offsets
    offsets = [(0, 0)] * n_question_tokens + precomputed["offsets"][text]
    offsets = offsets[: max_len - 1] + [(0, 0)]

    # Padding
    padding_length = max_len - len(input_ids)
    if padding_length > 0:
        input_ids = input_ids + ([tokens["pad"]] * padding_length)
        token_type_ids = token_type_ids + ([0] * padding_length)
        offsets = offsets + ([(0, 0)] * padding_length)

    encoding = {
        "input_ids": input_ids,
        "token_type_ids": token_type_ids,
        "offset_mapping": offsets,
    }

    return encoding

Dataset

继承dataset类必须重写__init__, __getitem__, __len__ 三个方法

import torch
import numpy as np
from torch.utils.data import Dataset


class PatientNoteDataset(Dataset):
    def __init__(self, df, tokenizer, max_len):
        self.df = df
        self.max_len = max_len
        self.tokenizer = tokenizer

        self.texts = df['clean_text'].values
        self.feature_text = df['feature_text'].values
        self.char_targets = df['target'].values.tolist()

    def __getitem__(self, idx):
        text = self.texts[idx]
        feature_text = self.feature_text[idx]
        char_target = self.char_targets[idx]

        # Tokenize
        if self.tokenizer.precomputed is None:
            encoding = self.tokenizer(
                feature_text,
                text,
                return_token_type_ids=True,
                return_offsets_mapping=True,
                return_attention_mask=False,
                truncation="only_second",
                max_length=self.max_len,
                padding='max_length',
            )
            raise NotImplementedError("fix issues with question offsets")
        else:
            encoding = encodings_from_precomputed(
                feature_text,
                text,
                self.tokenizer.precomputed,
                self.tokenizer,
                max_len=self.max_len
            )

        return {
            "ids": torch.tensor(encoding["input_ids"], dtype=torch.long),
            "token_type_ids": torch.tensor(encoding["token_type_ids"], dtype=torch.long),
            "target": torch.tensor([0], dtype=torch.float),
            "offsets": np.array(encoding["offset_mapping"]),
            "text": text,
        }

    def __len__(self):
        return len(self.texts)

Plot predictions

给预测中的span上色

import spacy
import numpy as np

def plot_annotation(df, pn_num):
    options = {"colors": {}}

    df_text = df[df["pn_num"] == pn_num].reset_index(drop=True)

    text = df_text["pn_history"][0]
    ents = []

    for spans, feature_text, feature_num in df_text[["span", "feature_text", "feature_num"]].values:
        for s in spans:
            ents.append({"start": int(s[0]), "end": int(s[1]), "label": feature_text})

        options["colors"][feature_text] =  f"rgb{tuple(np.random.randint(100, 255, size=3))}"

    doc = {"text": text, "ents": sorted(ents, key=lambda i: i["start"])}

    spacy.displacy.render(doc, style="ent", options=options, manual=True, jupyter=True)

Model

import torch
import transformers
import torch.nn as nn
from transformers import AutoConfig, AutoModel


class NERTransformer(nn.Module):
    def __init__(
        self,
        model,
        num_classes=1,
        config_file=None,
        pretrained=True,
    ):
        super().__init__()
        self.name = model
        self.pad_idx = 1 if "roberta" in self.name else 0

        transformers.logging.set_verbosity_error()

        if config_file is None:
            config = AutoConfig.from_pretrained(model, output_hidden_states=True)
        else:
            config = torch.load(config_file)

        if pretrained:
            self.transformer = AutoModel.from_pretrained(model, config=config)
        else:
            self.transformer = AutoModel.from_config(config)

        self.nb_features = config.hidden_size

#         self.cnn = nn.Identity()
        self.logits = nn.Linear(self.nb_features, num_classes)

    def forward(self, tokens, token_type_ids):
        """
        Usual torch forward function

        Arguments:
            tokens {torch tensor} -- Sentence tokens
            token_type_ids {torch tensor} -- Sentence tokens ids
        """
        hidden_states = self.transformer(
            tokens,
            attention_mask=(tokens != self.pad_idx).long(),
            token_type_ids=token_type_ids,
        )[-1]

        features = hidden_states[-1]

        logits = self.logits(features)

        return logits

Inference

Loads weights

import torch

def load_model_weights(model, filename, verbose=1, cp_folder="", strict=True):
    """
    Loads the weights of a PyTorch model. The exception handles cpu/gpu incompatibilities.

    Args:
        model (torch model): Model to load the weights to.
        filename (str): Name of the checkpoint.
        verbose (int, optional): Whether to display infos. Defaults to 1.
        cp_folder (str, optional): Folder to load from. Defaults to "".
        strict (bool, optional): Whether to allow missing/additional keys. Defaults to False.

    Returns:
        torch model: Model with loaded weights.
    """
    if verbose:
        print(f"\n -> Loading weights from {os.path.join(cp_folder,filename)}\n")

    try:
        model.load_state_dict(
            torch.load(os.path.join(cp_folder, filename), map_location="cpu"),
            strict=strict,
        )
    except RuntimeError:
        model.encoder.fc = torch.nn.Linear(model.nb_ft, 1)
        model.load_state_dict(
            torch.load(os.path.join(cp_folder, filename), map_location="cpu"),
            strict=strict,
        )

    return model

Predict

import torch
from torch.utils.data import DataLoader
from tqdm.notebook import tqdm


def predict(model, dataset, data_config, activation="softmax"):
    """
    Usual predict torch function
    """
    model.eval()

    loader = DataLoader(
        dataset,
        batch_size=data_config['val_bs'],
        shuffle=False,
        num_workers=NUM_WORKERS,
        pin_memory=True,
    )

    preds = []
    with torch.no_grad():
        for data in tqdm(loader):
            ids, token_type_ids = data["ids"], data["token_type_ids"]

            y_pred = model(ids.cuda(), token_type_ids.cuda())

            if activation == "sigmoid":
                y_pred = y_pred.sigmoid()
            elif activation == "softmax":
                y_pred = y_pred.softmax(-1)

            preds += [
                token_pred_to_char_pred(y, offsets) for y, offsets
                in zip(y_pred.detach().cpu().numpy(), data["offsets"].numpy())
            ]

    return preds

Inference

def inference_test(df, exp_folder, config, cfg_folder=None):
    preds = []

    if cfg_folder is not None:
        model_config_file = cfg_folder + config.name.split('/')[-1] + "/config.pth"
        tokenizer_folder = cfg_folder + config.name.split('/')[-1] + "/tokenizers/"
    else:
        model_config_file, tokenizer_folder = None, None

    tokenizer = get_tokenizer(
        config.name, precompute=config.precompute_tokens, df=df, folder=tokenizer_folder
    )

    dataset = PatientNoteDataset(
        df,
        tokenizer,
        max_len=config.max_len,
    )

    model = NERTransformer(
        config.name,
        num_classes=config.num_classes,
        config_file=model_config_file,
        pretrained=False
    ).cuda()
    model.zero_grad()

    weights = sorted(glob.glob(exp_folder + "*.pt"))
    for weight in weights:
        model = load_model_weights(model, weight)

        pred = predict(
            model,
            dataset,
            data_config=config.data_config,
            activation=config.loss_config["activation"]
        )
        preds.append(pred)

    return preds

Main

Config

class Config:
    # Architecture
    name = "roberta-large"
    num_classes = 1

    # Texts
    max_len = 310
    precompute_tokens = True

    # Training    
    loss_config = {
        "activation": "sigmoid",
    }

    data_config = {
        "val_bs": 16 if "large" in name else 32,
        "pad_token": 1 if "roberta" in name else 0,
    }

    verbose = 1

Data

在这里插入图片描述

Inference

在这里插入图片描述

Plot predictions

try:
    df_test['span'] = df_test['preds'].apply(char_target_to_span)
    plot_annotation(df_test, df_test['pn_num'][0])
except:
    pass

在这里插入图片描述
与deberta不同,空格不包括在偏移量中,我们需要手动添加,否则会影响性能

Post-processing

def post_process_spaces(target, text):
    target = np.copy(target)

    if len(text) > len(target):
        padding = np.zeros(len(text) - len(target))
        target = np.concatenate([target, padding])
    else:
        target = target[:len(text)]

    if text[0] == " ":
        target[0] = 0
    if text[-1] == " ":
        target[-1] = 0

    for i in range(1, len(text) - 1):
        if text[i] == " ":
            if target[i] and not target[i - 1]:  # space before
                target[i] = 0

            if target[i] and not target[i + 1]:  # space after
                target[i] = 0

            if target[i - 1] and target[i + 1]:
                target[i] = 1

    return target
df_test['preds_pp'] = df_test.apply(lambda x: post_process_spaces(x['preds'], x['clean_text']), 1)
try:
    df_test['span'] = df_test['preds_pp'].apply(char_target_to_span)
    plot_annotation(df_test, df_test['pn_num'][0])
except:
    pass

在这里插入图片描述

Submission

df_test['location'] = labels_to_sub(df_test['preds_pp'].values)

sub = pd.read_csv(DATA_PATH + 'sample_submission.csv')

sub = sub[['id']].merge(df_test[['id', "location"]], how="left", on="id")

sub.to_csv('submission.csv', index=False)

sub.head()

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Raki的NLP竞赛topline解读:NBME - Score Clinical Patient Notes 的相关文章

  • 理解含义的算法[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我想知道是否有任何特定的算法可以遵循
  • NLTK 中的 FreqDist 未对输出进行排序

    我是 Python 新手 我正在尝试自学语言处理 python 中的 NLTK 有一个名为 FreqDist 的函数 可以给出文本中单词的频率 但由于某种原因它无法正常工作 这是教程让我写的 fdist1 FreqDist text1 vo
  • Python 3 和 NLTK 与 WordNet 2.1 - 这可能吗?

    我将 Python 3 和 NLTK 3 0 0 与 WordNet 3 0 结合使用 我想用该数据 semval2007 https github com alvations pywsd tree master pywsd data se
  • NLTK CoreNLPDependencyParser:无法建立连接

    我正在尝试通过 NLTK 使用斯坦福解析器 按照示例here http www nltk org api nltk parse html nltk parse corenlp CoreNLPDependencyParser 20tutori
  • word2vec中单词的向量代表什么?

    word2vec https code google com p word2vec 是 Google 的开源工具 它为每个单词提供一个浮点值向量 它们到底代表什么 还有一篇论文关于段落向量 http cs stanford edu quoc
  • IOB 准确度和精密度之间的差异

    我正在使用命名实体识别和分块器对 NLTK 进行一些工作 我使用重新训练了分类器nltk chunk named entity py为此 我采取了以下措施 ChunkParse score IOB Accuracy 96 5 Precisi
  • 如何计算两个文本文档之间的相似度?

    我正在考虑使用任何编程语言 尽管我更喜欢 Python 来从事 NLP 项目 我想获取两个文档并确定它们的相似程度 常见的方法是将文档转换为 TF IDF 向量 然后计算它们之间的余弦相似度 任何有关信息检索 IR 的教科书都涵盖了这一点
  • scikit加权f1分数计算及使用

    我有一个关于weightedsklearn metrics f1 score 中的平均值 sklearn metrics f1 score y true y pred labels None pos label 1 average weig
  • 词干函数错误:词干需要一个位置参数

    这里的stem函数显示错误 指出stem需要循环中的一个位置参数 如所讨论的 from nltk stem import PorterStemmer as ps text my name is pythonly and looking fo
  • 将 python NLTK 解析树保存到图像文件[重复]

    这个问题在这里已经有答案了 这可能会复制这个 stackoverflowquestion https stackoverflow com questions 23429117 saving nltk drawn parse tree to
  • 实时跟踪每分钟/小时/天的前 100 个 Twitter 单词

    我最近遇到这样一个面试问题 Given a continuous twitter feed design an algorithm to return the 100 most frequent words used at this min
  • python中的语音识别持续时间设置问题

    我有一个 Wav 格式的音频文件 我想转录 我的代码是 import speech recognition as sr harvard sr AudioFile speech file wav with harvard as source
  • 将复数名词转换为单数名词

    如何使用 R 将复数名词转换为单数名词 我使用 tagPOS 函数来标记每个文本 然后提取所有标记为 NNS 的复数名词 但是如果我想将这些复数名词转换为单数该怎么办 library openNLP library tm acq o lt
  • 如何对德语文本进行词形还原?

    我有一篇德语文本 我想对其应用词形还原 如果不可能进行词形还原 那么我也可以接受词干提取 Data 这是我的德语文本 mails Hallo Ich spielte am fr hen Morgen und ging dann zu ein
  • 使用正则表达式标记化进行 NLP 词干提取和词形还原

    定义一个函数 名为performStemAndLemma 它需要一个参数 第一个参数 textcontent 是一个字符串 编辑器中给出了函数定义代码存根 执行以下指定任务 1 对给出的所有单词进行分词textcontent 该单词应包含字
  • 如何检测文本是否可读?

    我想知道是否有一种方法可以告诉给定的文本是人类可读的 我所说的人类可读的意思是 它有一些含义 格式就像某人写的文章 或者至少是由软件翻译器生成的供人类阅读的文章 这是背景故事 最近我正在制作一个应用程序 允许用户将短文本上传到数据库 在部署
  • 旧版本的 spaCy 在尝试安装模型时抛出“KeyError: 'package'”错误

    我在 Ubuntu 14 04 4 LTS x64 上使用 spaCy 1 6 0 和 python3 5 为了安装 spaCy 的英文版本 我尝试运行 这给了我错误消息 ubun ner 3 NeuroNER master src pyt
  • 举例解释bpe(字节对编码)?

    有人可以帮忙解释一下背后的基本概念吗BPE模型 除了这张纸 https arxiv org abs 1508 07909 目前还没有那么多解释 到目前为止我所知道的是 它通过将罕见和未知的单词编码为子词单元序列来实现开放词汇表上的 NMT
  • 斯坦福 CoreNLP:使用部分现有注释

    我们正在尝试利用现有的 代币化 句子分割 和命名实体标记 同时我们希望使用斯坦福 CoreNlp 额外为我们提供 词性标注 词形还原 和解析 目前 我们正在尝试以下方式 1 为 pos lemma parse 创建一个注释器 Propert
  • 如何从 Pandas DataFrame 转换为 Tensorflow BatchDataset 以进行 NLP?

    老实说 我想弄清楚如何转换数据集 格式 pandasDataFrame或 numpy 数组 转换为简单文本分类张量流模型可以训练用于情感分析的形式 我使用的数据集类似于 IMDB 包含文本和标签 正面或负面 我看过的每个教程要么以不同的方式

随机推荐

  • gethostbyname()函数详解

    基本概念 gethostbyname 函数主要作用 用域名或者主机名获取地址 操作系统提供的库函数 以下的讨论基于linux环境 域名系统 Domain Name System DNS 主要用于主机名字与IP地址之间的映射 每个组织机构往往
  • 【NLP】1、BERT

    文章目录 一 背景 二 方法 论文 BERT Pre training of Deep Bidirectional Transformers for Language Understanding 出处 Google 一 背景 在 BERT
  • flutter图片点击跳转_flutter页面跳转 Route 使用汇总

    一 push方式直接跳转 普通跳转 Navigator push context MaterialPageRoute builder BuildContext context gt Page1 复制代码 带参数跳转和接收参数 Navigat
  • Python习题四

    习题四 1 已知10个学生的成绩为68 75 32 99 78 45 88 72 83 78 请将成绩存放在列表中 请对其进行统计 输出优 100 89 良 89 80 中 79 60 差良 59 0 4个等级的人数 代码 运行 2 利用W
  • 代码质量管理工具:SonarQube常见的问题及正确解决方案

    SonarQube 简介 Sonar 是一个用于代码质量管理的开放平台 通过插件机制 Sonar 可以集成不同的测试工具 代码分析工具 以及持续集成工具 与持续集成工具 例如 Hudson Jenkins 等 不同 Sonar 并不是简单地
  • C#基于串行通讯不同计算机数据库之间数据交换系统(原创作品,送论文查重报告)

    论文编号 C 005 论文题目 基于串行通讯不同计算机数据库之间数据交换系统 开发语言 C 包括内容 论文 可执行程序 源码 答辩ppt 外文翻译 进度表 程序操作演示录像 数 据 库 SQL 论文字数 7000字以上
  • c++ 关于opencv 的基本操作

    读取影像 include
  • 没钱也能创业么?没钱怎样创业?

    一 先说结果不但并不是没钱就不能创业 反而是一切追求完美资本的人 无论有钱没钱 都能够且应当创业 二 界定问题我还在风投领域当上五六年兵线 眼界过上百个各式各样企业和创业者 项目投资总额度过亿人民币 也用掉过他人项目投资帮我的上百万用以创业
  • 组成最大数 华为机试

    题目描述 给定一组非负整数 重新排列它们的顺序使之组成一个最大的整数 示例 输入 10 2 输出 210 输入 3 30 34 5 9 输出 9534330 解题思路 回溯法 代码 package Huawei import java ut
  • Mysql分库分表实战(一)——一文搞懂Mysql数据库分库分表

    由于业务需要 需要对Mysql数据库进行分库分表 故而最近一直在整理分库分表的相关知识 现手上的工作也告一段落了 抽空将自己最近的学习结果转化为博文 分享给大家 本博文打算做成一个系列的 首先是分库分表的理论知识的了解 其次是基于Java编
  • 方差分析中怎么看有无显著性影响_一文带你轻松掌握,重复测量方差分析

    在某些实验研究中 常常需要考虑时间因素对实验的影响 当需要对同一观察单位在不同时间重复进行多次测量 每个样本的测量数据之间存在相关性 因而不能简单的使用方差分析进行研究 而需要使用重复测量方差分析 案例 当前有这样一项关于抑郁症的研究 共有
  • html中%20是什么意思?

    两个空格的话就是两个 20 转载于 https www cnblogs com linsx p 6943985 html
  • shell select用法

    select 是 Bash shell 中的一个命令 用于在终端中创建交互式菜单 select 语法格式如下 select varname in list do command1 command2 done 其中 varname 是一个变量
  • 竞争条件(race condition)

    在一些操作系统中 协作的进程可能共享一些彼此都能读写的公用存储区 这个公用存储区可能在内存中 可能是在内核数据结构中 也可能是一个共享文件 这里共享存储区的位置并不影响通信的本质及其带来的问题 为了理解实际中进程间通信如何工作 我们考虑一个
  • linux下五颜六色的文件——具体含义

    1 有一个伟人说过 Linux下一切都是文件 没错 他说的很对 但是文件又有很多汇总类型 Linux系统中用不同的颜色先大致区分一下 2 LINUX下不同的文件类型有不同的颜色 绿色文件 可执行文件 可执行的程序 红色文件 压缩文件或者包文
  • 【数论基础】—— 二项式定理

    二项式定理 内容 x y n
  • MySQL 使用方法简单教程

    目录 启动MySQL服务器 进入mysql交互操作界面 退出MySQL操作界面 第一条命令 多行语句 使用SHOW语句找出在服务器上当前存在什么数据库 创建一个数据库abccs 选择你所创建的数据库 创建一个数据库表 显示表的结构 查询所有
  • stm32cubemx 多路adc采集

    采用的软件是STM32CUBEMX KEIL5 硬件为stm32F103C8T6 我与原文作者做的区别在于 External Trigger Conversion Edge 我在进行配置的时间没有None选项 我选择的是默认的Regular
  • 线代矩阵相乘笔算的新简捷方法

    本矩阵相乘简捷笔算方法做法与传统本质一样 但对部分人来说这样列式子图更容易记忆和准确计算 O O 2013年12月写 2016年5月23日略修正 摘 矩阵的乘法定义 以前这种笔算方法太麻烦 难以快速看出所得矩阵的行列数或者是容易算少算多了一
  • Raki的NLP竞赛topline解读:NBME - Score Clinical Patient Notes

    Description 当你去看医生时 他们如何解释你的症状可以决定你的诊断是否准确 当他们获得执照时 医生们已经有了很多写病人笔记的练习 这些笔记记录了病人的主诉历史 体检结果 可能的诊断和后续护理 学习和评估写病人笔记的技能需要其他医生