天天看點

Python 文本資料處理

1 基本特征提取

import pandas as pd
train=pd.read_csv(".../train_E6oV3lV.csv")
print(train.head())
           

1.1 詞彙數量

我們可以簡單地調用split函數,将句子切分:

train['word_count']=train['tweet'].apply(lambda x:len(str(x).split(" ")))
train[['tweet','word_count']].head()
           

1.2 字元數量

train['char_count']=train['tweet'].str.len()
train[['tweet','char_count']].head()
           

注意這裡字元串的個數包含了推文中的空格個數,我們根據需要自行去除掉

1.3 平均詞彙長度

def avg_word(sentence):
    words=sentence.split()
    return (sum(len(word) for word in words)/len(words))
train['avg_word']=train['tweet'].apply(lambda x:avg_word(x))
train[['tweet','avg_word']].head()
           

1.4 停用詞的數量

通常情況下,在解決NLP問題時,首要任務時去除停用詞(stopword)。但是有時計算停用詞的數量可以提供我們之前失去的額外資訊。下面關于停用詞的解釋:

為節省存儲空間和提高搜尋效率,搜尋引擎在索引頁面或處理搜尋請求時會自動忽略某些字或詞,這些字或詞即被稱為Stop Words(停用詞)。通常意義上,Stop Words大緻為如下兩類:

  • 這些詞應用十分廣泛,在Internet上随處可見,比如“Web”一詞幾乎在每個網站上均會出現,對這樣的詞搜尋引擎無 法保證能夠給出真正相關的搜尋結果,難以幫助縮小搜尋範圍,同時還會降低搜尋的效率;
  • 這類就更多了,包括了語氣助詞、副詞、介詞、連接配接詞等,通常自身 并無明确的意義,隻有将其放入一個完整的句子中才有一定作用,如常見的“的”、“在”之類。

在這裡,我們導入NLTK庫中的stopwors子產品

from nltk.corpus import stopwords
stop=stopwords.words('english')
train['stopwords']=train['tweet'].apply(lambda sen:len([x for x in sen.split() if x in stop]))
train[['tweet','stopwords']].head()
           

1.5 特殊字元的數量

一個比較有趣的特征就是我們可以從每個推文中提取“#”和“@”符号的數量。這也有利于我們從文本資料中提取更多資訊

這裡我們使用

startswith

函數來處理

train['hashtags']=train['tweet'].apply(lambda sen:len([x for x in sen.split() if x.startswith("#")]))
train[['tweet','hashtags']].head()
           

1.6 數字的數量

這個特征并不常用,但是在做相似任務時,數字數量是一個比較有用的特征

train['numerics']=train['tweet'].apply(lambda sen:len([x for x in sen.split() if x.isdigit()]))
train[['tweet','numerics']].head()
           

1.7 大寫單詞的數量

“Anger”或者 “Rage”通常情況下使用大寫來表述,是以有必要去識别出這些詞

train['upper']=train['tweet'].apply(lambda sen:len([x for x in sen.split() if x.isupper()]))
train[['tweet','upper']].head()
           

2 文本資料的預處理

到目前為止,我們已經學會了如何從文本資料中提取基本特征。深入文本和特征提取之前,我們的第一步應該是清洗資料,以獲得更好的特性。

我們将實作這一目标做一些基本的訓練資料預處理步驟。

2.1 小寫轉化

預處理的第一步,我們要做的是把我們的推文變成小寫。這避免了擁有相同的多個副本。例如,當我們計算字詞彙數量時,“Analytics”和“analytics”将被視為不同的單詞。

train['tweet']=train['tweet'].apply(lambda sen:" ".join(x.lower() for x in sen.split()))
train['tweet'].head()
           

2.2 去除标點符号

下一步是去除标點符号,因為它在文本資料中不添加任何額外的資訊。是以删除的所有符号将幫助我們減少訓練資料的大小。

train['tweet'] = train['tweet'].str.replace('[^\w\s]','')
train['tweet'].head()
           

正如你所看到的在上面的輸出中,所有的标點符号,包括”#”和”@”已經從訓練資料中去除

2.3 停用詞去除

正如我們前面所讨論的,停止詞(或常見單詞)應該從文本資料中删除。為了這個目的,我們可以建立一個清單stopwords作為自己停用詞庫或我們可以使用預定義的庫。

from nltk.corpus import stopwords
stop=stopwords.words('english')
train['tweet']=train['tweet'].apply(lambda sen:" ".join(x for x in sen.split() if x not in stop))
train['tweet'].head()
           

2.4 常見詞去除

我們可以把常見的單詞從文本資料首先,讓我們來檢查中最常出現的10個字文本資料然後再調用删除或保留。

freq=pd.Series(' '.join(train['tweet']).split()).value_counts()[:]
           

現在我們把這些詞去除掉,因為它們對我們文本資料分類沒有任何作用

train['tweet']=train['tweet'].apply(lambda sen:' '.join(x for x in sen.split() if x not in freq))
train['tweet'].head()
           

2.5 稀缺詞去除

同樣,正如我們删除最常見的話說,這一次讓我們從文本中删除很少出現的詞。因為它們很稀有,它們之間的聯系和其他詞主要是噪音。可以替換罕見的單詞更一般的形式,然後這将有更高的計數。

freq = pd.Series(' '.join(train['tweet']).split()).value_counts()[-:]
           
freq = list(freq.index)
train['tweet'] = train['tweet'].apply(lambda x: " ".join(x for x in x.split() if x not in freq))
train['tweet'].head()
           

所有這些預處理步驟是必不可少的,幫助我們減少我們的詞彙噪音,這樣最終産生更有效的特征。

2.6 拼寫校對

我們都見過推文存在大量的拼寫錯誤。我們再短時間内匆忙發送tweet,很難發現這些錯誤。在這方面,拼寫校正是一個有用的預處理步驟,因為這也會幫助我們減少單詞的多個副本。例如,“Analytics”和“analytcs”将被視為不同的單詞,即使它們在同一意義上使用。

為實作這一目标,我們将使用textblob庫。

TextBlob是一個用Python編寫的開源的文本處理庫。它可以用來執行很多自然語言處理的任務,比如,詞性标注,名詞性成分提取,情感分析,文本翻譯,等等。你可以在官方文檔閱讀TextBlog的所有特性。

from textblob import TextBlob
train['tweet'][:5].apply(lambda x: str(TextBlob(x).correct()))
           

注意,它會花費很多時間去做這些修正。是以,為了學習的目的,我隻顯示這種技術運用在前5行的效果。

另外在使用這個技術之前,需要小心一些,因為如果推文中存在大量縮寫,比如“your”縮寫為“ur”,那麼将修正為“or”

2.7 分詞

分詞是指将文本劃分為一系列的單詞或詞語。在我們的示例中,我們使用了textblob庫

TextBlob(train['tweet'][1]).words
           

2.8 詞幹提取

詞形還原(lemmatization),是把一個任何形式的語言詞彙還原為一般形式(能表達完整語義),而詞幹提取

(stemming)是抽取詞的詞幹或詞根形式(不一定能夠表達完整語義)。詞形還原和詞幹提取是詞形規範化的兩類重要方式,都能夠達到有效歸并詞形的目的,二者既有聯系也有差別。具體介紹請參考詞幹提取(stemming)和詞形還原(lemmatization)

詞幹提取(stemming)是指通過基于規則的方法去除單詞的字尾,比如“ing”,“ly”,“s”等等。

from nltk.stem import PorterStemmer
st=PorterStemmer()
train['tweet'][:5].apply(lambda x:" ".join([st.stem(word) for word in x.split()]))
           

在上面的輸出中,“dysfunctional ”已經變為“dysfunct ”

2.9 詞性還原

詞形還原處理後獲得的結果是具有一定意義的、完整的詞,一般為詞典中的有效詞

from textblob import Word
train['tweet']=train['tweet'].apply(lambda x:" ".join([Word(word).lemmatize() for word in x.split()]))
train['tweet'].head()
           

3 進階文本處理

到目前為止,我們已經做了所有的可以清洗我們資料的預處理基本步驟。現在,我們可以繼續使用NLP技術提取特征。

3.1 N-grams

N-grams稱為N元語言模型,是多個詞語的組合,是一種統計語言模型,用來根據前(n-1)個item來預測第n個item。常見模型有一進制語言模型(unigrams)、二進制語言模型(bigrams )、三元語言模型(trigrams )。

Unigrams包含的資訊通常情況下比bigrams和trigrams少,需要根據具體應用選擇語言模型,因為如果n-grams太短,這時不能捕獲重要資訊。另一方面,如果n-grams太長,那麼捕獲的資訊基本上是一樣的,沒有差異性

TextBlob(train['tweet'][0]).ngrams(2)
           

3.2 詞頻

詞頻(Term frequency)就是一個單詞在一個句子出現的次數與這個句子單詞個數的比例。

TF = (Number of times term T appears in the particular row) / (number of terms in that row)

tf1 = (train['tweet'][1:2]).apply(lambda x: pd.value_counts(x.split(" "))).sum(axis = 0).reset_index()
tf1.columns = ['words','tf']
tf1
           

3.3 反轉文檔頻率

反轉文檔頻率(Inverse Document Frequency),簡稱為IDF,其原理可以簡單了解為如果一個單詞在所有文檔都會出現,那麼可能這個單詞對我們沒有那麼重要。

一個單詞的IDF就是所有行數與出現該單詞的行的個數的比例,最後對數。

idf=log(Nn) i d f = l o g ( N n )

import numpy as np
for i,word in enumerate(tf1['words']):
    tf1.loc[i, 'idf'] =np.log(train.shape[]/(len(train[train['tweet'].str.contains(word)])))
tf1
           

3.4 詞頻-反轉文檔頻率(TF-IDF)

TF-IDF=TF*IDF

tf1['tfidf']=tf1['tf']*tf1['idf']
tf1
           

我們可以看到,TF-IDF已經“懲罰了”‘don’t’, ‘can’t’, 和‘use’,因為它們是通用詞,tf-idf的值都比較低。

另外可以通過sklearn直接計算tf-idf值

from sklearn.feature_extraction.text import TfidfVectorizer
tfidf = TfidfVectorizer(max_features=, lowercase=True,analyzer='word',stop_words= 'english',ngram_range=(,))
train_vect = tfidf.fit_transform(train['tweet'])
train_vect
           

3.5 詞袋

BOW,就是将文本/Query看作是一系列詞的集合。由于詞很多,是以咱們就用袋子把它們裝起來,簡稱詞袋。至于為什麼用袋子而不用筐(basket)或者桶(bucket),這咱就不知道了。舉個例子:

蘇甯易購/是/國内/著名/的/B2C/電商/之一
           

這是一個短文本。“/”作為詞與詞之間的分割。從中我們可以看到這個文本包含“蘇甯易購”,“B2C”,“電商”等詞。換句話說,該文本的的詞袋由“蘇甯易購”,“電商”等詞構成。

詳細請參考詞袋模型和詞向量模型

from sklearn.feature_extraction.text import CountVectorizer
bow = CountVectorizer(max_features=, lowercase=True, ngram_range(,), analyzer = "word")
train_bow = bow.fit_transform(train['tweet'])
train_bow
           

3.6 情感分析

我們最終需要解決的任務就是如何對推文進行情感分析,在使用ML/DL模型之前,我們可以使用textblob庫去進行評測情感

train['tweet'][:5].apply(lambda x:TextBlob(x).sentiment)
           

使用TextBlob情感分析的結果,以元組的方式進行傳回,形式如(polarity, subjectivity). 其中polarity的分數是一個範圍為 [−1.0,1.0] [ − 1.0 , 1.0 ] 浮點數, 正數表示積極,負數表示消極。subjectivity 是一個 範圍為 [0.0,1.0] [ 0.0 , 1.0 ] 的浮點數,其中 0.0 0.0 表示 客觀, 1.0 1.0 表示主觀的。

下面是一個簡單執行個體

from textblob import TextBlob
testimonial = TextBlob("Textblob is amazingly simple to use. What great fun!")
print(testimonial.sentiment)
           
train['sentiment'] = train['tweet'].apply(lambda x: TextBlob(x).sentiment[] )
train[['id','tweet','sentiment']].head()
           

4.7 詞嵌入

詞嵌入就是文本的向量化表示,潛在思想就是相似單詞的向量之間的距離比較短。

from gensim.scripts.glove2word2vec import glove2word2vec
glove_input_file = 'glove.6B.100d.txt'
word2vec_output_file = 'glove.6B.100d.txt.word2vec'
glove2word2vec(glove_input_file, word2vec_output_file)