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就是所有行數與出現該單詞的行的個數的比例,最後對數。
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的分數是一個範圍為 浮點數, 正數表示積極,負數表示消極。subjectivity 是一個 範圍為 的浮點數,其中表示 客觀,表示主觀的。
下面是一個簡單例項
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)