1. 程式人生 > >Python 文字資料處理

Python 文字資料處理

1 基本特徵提取

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

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()[:10]

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

freq=list(freq.index)
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()[-10:]
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
WordList(['thanks', 'lyft', 'credit', 'cant', 'use', 'cause', 'dont', 'offer', 'wheelchair', 'vans', 'pdx', 'disapointed', 'getthanked'])

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)
import numpy as np
for i,word in enumerate(tf1['words']):
    tf1.loc[i, 'idf'] =np.log(train.shape[0]/(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=1000, lowercase=True,analyzer='word',stop_words= 'english',ngram_range=(1,1))
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=1000, lowercase=True, ngram_range(1,1), 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]浮點數, 正數表示積極,負數表示消極。subjectivity 是一個 範圍為[0.0,1.0] 的浮點數,其中0.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[0] )
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)