Clasificación de documentos: 7 enfoques prácticos para pequeños conjuntos de datos

La clasificación de documentos o texto es una de las tareas más importantes en el procesamiento del lenguaje natural (PNL).


Tiene muchos usos, como categorizar noticias, filtrar spam, buscar comentarios inapropiados, etc.


Las grandes empresas no tienen problemas para recopilar grandes conjuntos de datos, por lo que aprender un modelo de clasificación de texto desde cero es una tarea factible.


Sin embargo, para la mayoría de las tareas del mundo real, los conjuntos de datos grandes son raros y debe ser inteligente para construir su modelo.


En este artículo hablaré sobre enfoques prácticos para las transformaciones de texto que permitirán clasificar documentos, incluso si el conjunto de datos es pequeño.


Introducción a la clasificación de documentos


El proceso de clasificación de documentos comienza con la limpieza y preparación del cuerpo.
Luego, este cuerpo se codifica con cualquier tipo de representación de texto, después de lo cual puede comenzar a modelar.



En este artículo, nos centraremos en el paso "Presentación de texto" de este diagrama.


Conjunto de datos de prueba para clasificación


Utilizaremos los datos de la competencia ¿ Verdadero o no? PNL con tuits de desastre de Kaggle .


El desafío es predecir qué tweets fueron sobre desastres reales y cuáles no.


Si desea repetir el artículo paso a paso, no olvide instalar las bibliotecas utilizadas en él.


:


import pandas as pd

tweet= pd.read_csv('../input/nlp-getting-started/train.csv')
test=pd.read_csv('../input/nlp-getting-started/test.csv')

tweet.head(3)


, , , .


.


print('There are {} rows and {} columns in train'.format(tweet.shape[0],tweet.shape[1]))
print('There are {} rows and {} columns in test'.format(test.shape[0],test.shape[1]))

8000 .


, 280 .



, NLP, .


, , , .


, :


  • — .
  • - — «a» «the».
  • — («studies», «studing» → «study»).

def preprocess_news(df):
    '''Function to preprocess and create corpus'''
    new_corpus=[]

    lem=WordNetLemmatizer()
    for text in df["question_text"]:
        words=[w for w in word_tokenize(text) if (w not in stop)]

        words=[lem.lemmatize(w) for w in words]

        new_corpus.append(words)
    return new_corpus

corpus=preprocess_news(df)

, , .



, .


.


CountVectorizer


CountVectorizer — .


, , .


:


text = ["She sells seashells in the seashore"]
# create the transform
vectorizer = CountVectorizer()
# tokenize and build vocab
vectorizer.fit(text)
# summarize
print(vectorizer.vocabulary_)
# encode document
vector = vectorizer.transform(text)
# summarize encoded vector
print(vector.shape)
print(type(vector))
print(vector.toarray())


, CountVectorizer Numpy, .


, , .


vector=vectorizer.transform(["I sell seashells in the seashore"])
vector.toarray()


, :


  • 3 4 , . , .

, — «sells» «she».


CountVectorizer, .


vec=CountVectorizer(max_df=10,max_features=10000)
vec.fit(df.question_text.values)
vector=vec.transform(df.question_text.values)

, CountVectorizer , :


  • max_features — n , .
  • min_df — , .
  • max_df — , .

( ).


TfidfVectorizer


Countvectorizer , , "the" ( ) .


— TfidfVectorizer.


Term frequency-inverse document frequency ( — ).


  • (Term Frequency) — , .


  • (Inverse Document Frequency) — , .



:


from sklearn.feature_extraction.text import TfidfVectorizer
# list of text documents
text = ["She sells seashells by the seashore","The sea.","The seashore"]
# create the transform
vectorizer = TfidfVectorizer()
# tokenize and build vocab
vectorizer.fit(text)
# summarize
print(vectorizer.vocabulary_)
print(vectorizer.idf_)
# encode document
vector = vectorizer.transform([text[0]])
# summarize encoded vector
print(vector.shape)
print(vector.toarray())


6 , «the», 4 .


0 1, - .


Word2vec


, .


(embeddings) .


n- .



Word2Vec Google .


, .


, , .


«The cat sat on the mat».



Word2vec :


  • (Continuous Bag of Words, CBoW) — , .


  • Skip-Gram.



, , , . word2vec python:


import gensim
from gensim.models import Word2Vec

model = gensim.models.Word2Vec(corpus, 
                               min_count = 1, size = 100, window = 5)

, word2vec.


:


  • size — .
  • min_count —  .
  • window — , . .

.


.


.


, gensim.


from  gensim.models.KeyedVectors import load_word2vec_format

def load_word2vec():
    word2vecDict = load_word2vec_format(
        '../input/word2vec-google/GoogleNews-vectors-negative300.bin',
        binary=True, unicode_errors='ignore')
    embeddings_index = dict()
    for word in word2vecDict.wv.vocab:
        embeddings_index[word] = word2vecDict.word_vec(word)

    return embeddings_index

:


w2v_model=load_word2vec()
w2v_model['London'].shape


, 300- .


( — , . , , . . )
, .


FastText


Genism — FastText.


Facebook .


Continuous Bag of Words Skip-Gram.
FastText , n-.


, , «orange».


«ora», «ran», «ang», «nge» ( ).


( ) «orange» n-.


, n- .


, «stupedofantabulouslyfantastic», , , , genism , .


FastText , , .


«fantastic» «fantabulous».


, .


.


n- .


.


from gensim.models import FastText 

def load_fasttext():

    print('loading word embeddings...')
    embeddings_index = {}
    f = open('../input/fasttext/wiki.simple.vec',encoding='utf-8')
    for line in tqdm(f):
        values = line.strip().rsplit(' ')
        word = values[0]
        coefs = np.asarray(values[1:], dtype='float32')
        embeddings_index[word] = coefs
    f.close()
    print('found %s word vectors' % len(embeddings_index))

    return embeddings_index

embeddings_index=load_fastext()


:


embeddings_index['london'].shape


GloVe


GloVe (global vectors for word representation) « ».


, .


, .


word2vec, .


.
.


.


.


, .


n- .


:



.


.


:


def load_glove():
    embedding_dict = {}
    path = '../input/glove-global-vectors-for-word-representation/glove.6B.100d.txt'
    with open(path, 'r') as f:
        for line in f:
            values = line.split()
            word = values[0]
            vectors = np.asarray(values[1:], 'float32')
            embedding_dict[word] = vectors
    f.close()

    return embedding_dict

embeddings_index = load_glove()

, , GloVe.


- .


embeddings_index['london'].shape



.
.
.


, .


:


  • .
  • .
  • .

, .


.


.


Tensorflow.


module_url = "../input/universalsentenceencoderlarge4"
# Import the Universal Sentence Encoder's TF Hub module
embed = hub.load(module_url)

.


sentence_list=df.question_text.values.tolist()
sentence_emb=embed(sentence_list)['outputs'].numpy()

.


Elmo, BERT


, .


.


«stick», «», «» , , .


NLP BERT , . .



, Keras .


, .


, Keras Tokenizer pad_sequences.


MAX_LEN=50
tokenizer_obj=Tokenizer()
tokenizer_obj.fit_on_texts(corpus)
sequences=tokenizer_obj.texts_to_sequences(corpus)

tweet_pad=pad_sequences(sequences,
                        maxlen=MAX_LEN,
                        truncating='post',
                        padding='post')

.


word_index=tokenizer_obj.word_index
print('Number of unique words:',len(word_index))

, .


.


def prepare_matrix(embedding_dict, emb_size=300):
    num_words = len(word_index)
    embedding_matrix = np.zeros((num_words, emb_size))

    for word, i in tqdm(word_index.items()):
        if i > num_words:
            continue

    emb_vec = embedding_dict.get(word)
    if emb_vec is not None:
        embedding_matrix[i] = emb_vec

    return embedding_matrix

.


trainable=False, .


def new_model(embedding_matrix):
    inp = Input(shape=(MAX_LEN,))

    x = Embedding(num_words, embedding_matrix.shape[1], weights=[embedding_matrix],
                  trainable=False)(inp)

    x = Bidirectional(
        LSTM(60, return_sequences=True, name='lstm_layer', 
             dropout=0.1, recurrent_dropout=0.1))(x)

    x = GlobalAveragePool1D()(x)
    x = Dense(1, activation="sigmoid")(x)
    model = Model(inputs=inp, outputs=x)

    model.compile(loss='binary_crossentropy',
                  optimizer='adam',
                  metrics=['accuracy'])

    return model

, , word2vec:


embeddings_index=load_word2vec()
embedding_matrix=prepare_matrix(embeddings_index)
model=new_model(embedding_matrix)

history=model.fit(X_train,y_train,
                  batch_size=8,
                  epochs=5,
                  validation_data=(X_test,y_test),
                  verbose=2)


, .



?


Neptune .



Los archivos adjuntos GloVe en los conjuntos de datos de prueba tuvieron un rendimiento ligeramente mejor que los otros dos archivos adjuntos.


Quizás logre más si personaliza aún más el modelo y limpia los datos.


Puedes ver los experimentos aquí .


Conclusión


En este artículo, examinamos e implementamos varios métodos para presentar atributos para la clasificación de texto utilizados cuando se trabaja con pequeños conjuntos de datos.


Espero que sean útiles en sus proyectos.


All Articles