姓名:閆偉? 學號:15020150038
轉載自:https://zhuanlan.zhihu.com/p/47341761
【嵌牛導讀】:自然語言處理專家 Rodolfo Ferro 可以通過Python來對一個人的情感進行分析畦浓。
【嵌牛鼻子】:Python Pandas Numpy?
【嵌牛提問】:如何用 Python 完成情感分析
【嵌牛正文】:
在本文我們會學習以下三方面內容:
使用 Tweepy 提取 Twitter 數據填帽,學習如何用 Pandas 處理數據
使用 Numpy谴蔑,Matplotlib 和 Seaborn 完成一些簡單的統(tǒng)計和可視化工作
使用 Textblob 對提取的特朗普的推文進行情感分析
項目代碼地址見文末。
我們需要什么悯恍?
首先展氓,我們需要安裝 Python适掰。
我(作者 Rodolfo Ferro——譯者注)使用的是 Python 3.6,不過所有代碼在 Python 2.7 上應該也都能運行始锚。強烈推薦安裝 Anaconda,這是個非常有用的 Python 包管理平臺喳逛,內置了很多有用的工具疼蛾,比如 Jupyter Notebooks。我會用 Jupyter Notebook 講解本文的代碼艺配,如果你在用其它的文本編輯器察郁,也能跑一些簡單的腳本,只是需要做些適配(不難)转唉。
我們需要安裝的環(huán)境依賴包括:
Numpy:使用 Python 進行科學計算的基本工具包皮钠。此外,Numpy 也可以用作通用數據的高效多維容器赠法。
Pandas:開源庫麦轰,提供高性能乔夯、易于使用的數據結構和數據分析工具。
Tweepy:一個使用方便的 Python 庫款侵,用于獲取 Twitter API末荐。
Matplotlib:一個 Python 2D 繪圖庫,可生成多種格式的高質量圖形新锈。
Seaborn:基于 matplotlib 的 Python 可視化庫甲脏,提供的 API 可繪制美觀的統(tǒng)計圖形。
Textblob:用于執(zhí)行文本數據處理的 Python 庫妹笆,提供的 API 可執(zhí)行常見的自然語言處理任務块请。
以上環(huán)境依賴都通過 pip 安裝。待安裝完所有軟件包后拳缠,開始寫代碼墩新!
1 提取推特數據(Tweepy+Pandas)
導入庫
這一步很簡單,將如下代碼復制到你的 Jupyter Notebook 上就行:
# General:import tweepy? ? ? ? ? # 用來使用推特APIimport pandas as pd? ? # 用來處理數據import numpy as np? ? ? # 用來計算數字# 用來繪圖和可視化from IPython.display import displayimport matplotlib.pyplot as pltimport seaborn as sns%matplotlib inline
很好窟坐!下載運行該代碼塊海渊,進入下個部分。
創(chuàng)建一個推特應用
要想提取推文用于分析哲鸳,我們需要登錄我們的推特開發(fā)者賬號臣疑,并創(chuàng)建一個應用。進行這項操作的網站地址是:https://apps.twitter.com/帕胆。沒有賬號的話朝捆,就注冊一個。
從這個我們在創(chuàng)建的應用中懒豹,會將如下信息保存為一個叫credentials.py的腳本中:
消費方密鑰(Consumer Key)
消費方機密(Consumer Secret)
訪問令牌密鑰(Access Token Key)
訪問令牌機密(Access Token Secret)
該操作的代碼示例:
# Twitter App access keys for @user# Consume:CONSUMER_KEY? ? = ''CONSUMER_SECRET = ''# Access:ACCESS_TOKEN? = ''ACCESS_SECRET = ''
額外創(chuàng)建這個文件的原因是我們只想導出這些變量的值芙盘,但在我們的主代碼(Notebook)中看不見。現在我們可以使用 Twitter API 了脸秽,為此需要創(chuàng)建一個允許我們進行密鑰身份驗證的函數儒老。我們會在另一個代碼單元中調用此函數,并運行它:
# 導入訪問密鑰:from credentials import * ? ?
# This will allow us to use the keys as variables
# API設置:def twitter_setup():? ? """? ? Utility function to setup the Twitter's API? ? with our access keys provided.? ? """? ? # 用密鑰授權和訪問: ? ?
auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET) ? ?
auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET) ? ?
# 用訪問返回API:? ? api = tweepy.API(auth)return api
目前為止還是很簡單的记餐,對吧驮樊?在下個部分我們開始提取推文。
推文提取
現在片酝,我們創(chuàng)建一個函數來設置推特 API囚衔,可以用該函數創(chuàng)建一個“extractor”對象。然后我們會使用 Tweepy 的函數 extractor.user_timeline(screen_name, count) 從 screen_name 的用戶中提取 count 數量的推文雕沿。
在文章標題里也說過了练湿,我們本文選擇川普的推文作為素材,從中提取數據進行情感分析审轮。沒辦法肥哎,誰叫他推特發(fā)的那么頻繁呢辽俗。
提取推特數據的方法如下:
# 創(chuàng)建一個extractor對象extractor = twitter_setup()# 創(chuàng)建一個推文列表tweets = extractor.user_timeline(screen_name="realDonaldTrump", count=200)print("Number of tweets extracted: {}.\n".format(len(tweets)))# 打印最近的5條推文print("5 recent tweets:\n")for tweet in tweets[:5]:? ? print(tweet.text)print()
有了這個,我們會得到一個與之類似的輸出篡诽,并且將該輸出和推特賬號進行比較(用以檢查我們是否保持一致):
提取的推文數量:200
最近的 5 條推文:
On behalf of @FLOTUS Melania & myself, THANK YOU for today's update & GREAT WORK! #SouthernBaptist @SendRelief,…https://t.co/4yZCeXCt6n
I will be going to Texas and Louisiana tomorrow with First Lady. Great progress being made! Spending weekend working at White House.
Stock Market up 5 months in a row!
'President Donald J. Trump Proclaims September 3, 2017, as a National Day of Prayer' #HurricaneHarvey #PrayForTexas…https://t.co/tOMfFWwEsN
Texas is healing fast thanks to all of the great men & women who have been working so hard. But still so much to do. Will be back tomorrow!
現在我們有了提取程序以及提取后的數據崖飘,均位于 tweets 變量中。這里必須說一句杈女,該列表中的每個元素都是一個來自 Tweepy 的 tweet 對象朱浴,我們會在下部分學習怎樣處理該數據。
創(chuàng)建(Pandas)DataFrame
現在我們用初始信息構造一個 Pandas DataFrame碧信,從而能以很容易的方式處理信息赊琳。
Ipython 的 display 函數會以很淺顯易懂的方式繪制出輸出結果街夭,dataframe 的 head 方法則能讓我們可視化該 dataframe 的前 5 個元素(或作為參數傳遞的第一個參數)砰碴。
所以,使用 Python 的列表表達式:
# 創(chuàng)建一個Pandas dataframedata = pd.DataFrame(data=[tweet.text for tweet in tweets], columns=['Tweets'])# 展示dataframe的前10個元素display(data.head(10))
這會創(chuàng)建一個與此類似的輸出:
<img src="https://pic1.zhimg.com/v2-48c19a5087b82cbcfb899266c88437a4_b.jpg" data-caption="" data-size="normal" data-rawwidth="707" data-rawheight="625" class="origin_image zh-lightbox-thumb" width="707" data-original="https://pic1.zhimg.com/v2-48c19a5087b82cbcfb899266c88437a4_r.jpg">
現在我們獲得了一個數據排列有序的干凈圖表板丽。
一個有趣的地方就是 Tweepy 中 tweets 結構具有的內部方法數量:
# 單個tweet對象中的內部方法print(dir(tweets[0]))
這會輸出如下元素列表:
['class', 'delattr', 'dict', 'dir', 'doc', 'eq', 'format', 'ge', 'getattribute', 'getstate', 'gt', 'hash', 'init', 'init_subclass', 'le', 'lt', 'module', 'ne', 'new', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'str', 'subclasshook', 'weakref', '_api', '_json', 'author', 'contributors', 'coordinates', 'created_at', 'destroy', 'entities', 'favorite', 'favorite_count', 'favorited', 'geo', 'id', 'id_str', 'in_reply_to_screen_name', 'in_reply_to_status_id', 'in_reply_to_status_id_str', 'in_reply_to_user_id', 'in_reply_to_user_id_str', 'is_quote_status', 'lang', 'parse', 'parse_list', 'place', 'possibly_sensitive', 'retweet', 'retweet_count', 'retweeted', 'retweets', 'source', 'source_url', 'text', 'truncated', 'user']
這里比較有意思的部分就是每條推文中所包含的元數據數量呈枉,如果我們想獲取像發(fā)推日期或發(fā)推源這樣的數據,我們就可以用該屬性獲取信息埃碱。下面是一個例子:
print(tweets[0].id)print(tweets[0].created_at)print(tweets[0].source)print(tweets[0].favorite_count)print(tweets[0].retweet_count)print(tweets[0].geo)print(tweets[0].coordinates)print(tweets[0].entities)
獲取一個這樣的輸出:
9037781308501319702017-09-02 00:34:32Twitter for iPhone245725585NoneNone{'hashtags': [{'text': 'SouthernBaptist', 'indices': [90, 106]}], 'symbols': [], 'user_mentions': [{'screen_name': 'FLOTUS', 'name': 'Melania Trump', 'id': 818876014390603776, 'id_str': '818876014390603776', 'indices': [13, 20]}, {'screen_name': 'sendrelief', 'name': 'Send Relief', 'id': 3228928584, 'id_str': '3228928584', 'indices': [107, 118]}], 'urls': [{'url': 'https://t.co/4yZCeXCt6n', 'expanded_url': 'https://twitter.com/i/web/status/903778130850131970', 'display_url': 'twitter.com/i/web/status/9…', 'indices': [121, 144]}]}
現在我們整理相關數據猖辫,并將其添加到我們的dataframe中。
將相關信息添加至Dataframe中
可以看到砚殿,我們能從單條推特中獲取很多數據啃憎,但并非所有數據都對我們有用。我們這里只需要向 dataframe 中添加部分數據似炎。我們會使用 Python 列表表達式辛萍,并為 dataframe 添加一個新列,只需在方括號之間添加內容名稱并分配內容即可羡藐。代碼如下:
# 添加相關數據data['len']? = np.array([len(tweet.text) for tweet in tweets])data['ID']? = np.array([tweet.id for tweet in tweets])data['Date'] = np.array([tweet.created_at for tweet in tweets])data['Source'] = np.array([tweet.source for tweet in tweets])data['Likes']? = np.array([tweet.favorite_count for tweet in tweets])data['RTs']? ? = np.array([tweet.retweet_count for tweet in tweets])
要想再次展示 dataframe 查看變化贩毕,只需:
# 展示dataframe中的前10個元素display(data.head(10))
<img src="https://pic1.zhimg.com/v2-29b2bcaec6fe11c18d5509983be50d54_b.jpg" data-caption="" data-size="normal" data-rawwidth="800" data-rawheight="1301" class="origin_image zh-lightbox-thumb" width="800" data-original="https://pic1.zhimg.com/v2-29b2bcaec6fe11c18d5509983be50d54_r.jpg">
現在我們提取出了數據,也將數據進行了整理仆嗦,方便處理辉阶。下面我們進一步處理數據,可視化一些圖表瘩扼,并收集一些統(tǒng)計數據谆甜。本文的第一部分就算完成了。
2 可視化和基本統(tǒng)計
平均值和受歡迎度
我們首先計算一些基本的統(tǒng)計數據集绰,比如所有推文字符長度的平均值规辱,被點贊和轉發(fā)次數最多的推文,等等倒慧。
現在我們只需在代碼下面添加一些輸入代碼和輸出按摘。
使用 Numpy 獲得平均值:
# 提取長度平均值mean = np.mean(data['len'])print("The lenght's average in tweets: {}".format(mean))
推文的平均長度為:125.925
為了能提取更多數據包券,我們使用 Pandas 的一些功能:
# 提取點贊數和轉發(fā)數最多的推文fav_max = np.max(data['Likes'])rt_max? = np.max(data['RTs'])fav = data[data.Likes == fav_max].index[0]rt? = data[data.RTs == rt_max].index[0]# 點贊數最多:print("The tweet with more likes is: \n{}".format(data['Tweets'][fav]))print("Number of likes: {}".format(fav_max))print("{} characters.\n".format(data['len'][fav]))# 轉發(fā)數最多:print("The tweet with more retweets is: \n{}".format(data['Tweets'][rt]))print("Number of retweets: {}".format(rt_max))print("{} characters.\n".format(data['len'][rt]))
點贊更多的推文是:
The United States condemns the terror attack in Barcelona, Spain, and will do whatever is necessary to help. Be tough & strong, we love you!
點贊數:222205
字數:144
轉發(fā)數更多的推文是:
The United States condemns the terror attack in Barcelona, Spain, and will do whatever is necessary to help. Be tough & strong, we love you!
轉發(fā)數:66099
字數:144
一個很常見的事就是“點贊數更多的推文,轉發(fā)數同樣更多”炫贤,不過也不是每回都這樣溅固。我們使用 Numpy 的 max 函數找出‘likes’列里面的最大點贊數和‘RTs’中的最大轉發(fā)數,只需尋找兩列中每一列里滿足最大值條件的索引兰珍。由于轉發(fā)數與點贊數(最大值)相同的推文可能不止一條侍郭,我們只需取用找到的第一個結果,所以我們使用 .index[0] 將索引分配給變量 fa 和 rt掠河。要想輸出滿足條件的推文亮元,我們訪問數據的方式和訪問矩陣或任何索引對象的方式是一樣的。
下面準備畫點圖唠摹。
時序
Pandas 內置了用于時序的對象爆捞。因為我們有帶有發(fā)推日期的整個向量,所以分別按照推文長度勾拉、點贊數和轉發(fā)數來構造數據的時序煮甥。
操作方式為:
# 創(chuàng)建數據的時序tlen = pd.Series(data=data['len'].values, index=data['Date'])tfav = pd.Series(data=data['Likes'].values, index=data['Date'])tret = pd.Series(data=data['RTs'].values, index=data['Date'])
如果我們想繪制出時序,可以使用 Pandas 在對象中的方法藕赞。繪制方法如下:
# 隨著時間推移的長度tlen.plot(figsize=(16,4), color='r');
這會得到如下輸出:
<img src="https://pic1.zhimg.com/v2-e48b414acba2937e14f2b6247d4eba4c_b.jpg" data-caption="" data-size="normal" data-rawwidth="880" data-rawheight="254" class="origin_image zh-lightbox-thumb" width="880" data-original="https://pic1.zhimg.com/v2-e48b414acba2937e14f2b6247d4eba4c_r.jpg">
在同一圖表中繪出點贊數和轉發(fā)數對比的方式為:
tfav.plot(figsize=(16,4), label="Likes", legend=True)tret.plot(figsize=(16,4), label="Retweets", legend=True);
得到如下輸出:
<img src="https://pic2.zhimg.com/v2-08589dc64053f8b6b785f07f72330281_b.jpg" data-caption="" data-size="normal" data-rawwidth="880" data-rawheight="245" class="origin_image zh-lightbox-thumb" width="880" data-original="https://pic2.zhimg.com/v2-08589dc64053f8b6b785f07f72330281_r.jpg">
以餅狀圖表示發(fā)推源
本文的第二部分我們就快完成了成肘,現在我們用餅狀圖繪制出發(fā)推設備來源,因為我們發(fā)現并非每條推文都是相同的來源斧蜕。首先清洗所有來源:
# 獲得所有可能來源sources = []for source in data['Source']:? ? if source not in sources:? ? ? ? sources.append(source)# 打印來源列表print("Creation of content sources:")for source in sources:print("* {}".format(source))
獲得了如下輸出后双霍,我們意識到特朗普的推文基本來自以下兩個來源:
iPhone
Media Studio
現在我們計算每個來源的數量,并為之創(chuàng)建一個餅狀圖批销。有些朋友可能注意到這段代碼不是很好洒闸,但是先湊合看吧,我是凌晨 4 點多熬夜寫的···
# 創(chuàng)建映射到標簽的Numpy向量percent = np.zeros(len(sources))for source in data['Source']:? ? for index in range(len(sources)):? ? ? ? if source == sources[index]:? ? ? ? ? ? percent[index] += 1? ? ? ? ? ? passpercent /= 100# 餅狀圖pie_chart = pd.Series(percent, index=sources, name='Sources')pie_chart.plot.pie(fontsize=11, autopct='%.2f', figsize=(6, 6));
這里會得到如下輸出:
<img src="https://pic3.zhimg.com/v2-025363815167c86b86b1e884a5ef1f46_b.jpg" data-caption="" data-size="normal" data-rawwidth="880" data-rawheight="334" class="origin_image zh-lightbox-thumb" width="880" data-original="https://pic3.zhimg.com/v2-025363815167c86b86b1e884a5ef1f46_r.jpg">
然后就可以看到發(fā)推源的占比风钻。
接下來完成本文的最后一部分——情感分析顷蟀。
3 情感分析
導入 Textblob
前面在開頭說過,Textblob 能讓我們以很簡單的方式執(zhí)行情感分析骡技。我們也會使用 Python 中的 re 庫鸣个,可用于處理正則表達式。這里我得分享兩個實用函數:a) 清洗文本(意思是任何與字母數字值不同的符號將重新映射到滿足此條件的新符號)b) 創(chuàng)建一個分類器布朦,在清洗文本后分析每條推文的歸一性囤萤。這里就不再深入解釋每種函數的具體工作原理了,因為那就扯遠了是趴,看官方文檔應該就明白了:
https://docs.python.org/3/library/re.html
代碼如下:
from textblob import TextBlobimport redef clean_tweet(tweet):? ? '''? ? Utility function to clean the text in a tweet by removing? ? links and special characters using regex.? ? '''? ? return ' '.join(re.sub("(@[A-Za-z0-9]+)|([^0-9A-Za-z \t])|(\w+:\/\/\S+)", " ", tweet).split())def analize_sentiment(tweet):? ? '''? ? Utility function to classify the polarity of a tweet? ? using textblob.? ? '''? ? analysis = TextBlob(clean_tweet(tweet))? ? if analysis.sentiment.polarity > 0:? ? ? ? return 1? ? elif analysis.sentiment.polarity == 0:? ? ? ? return 0? ? else:? ? ? ? return -1
因為 Textblob 提供訓練好的分析器涛舍,所以事情就好辦多了。Textblob 能使用多種不同的自然語言處理模型唆途。如果你想訓練你自己的分類器(或者想知道它的工作方式)富雅,點擊這個鏈接:
https://textblob.readthedocs.io/en/dev/classifiers.html
效果應該差不多掸驱,因為我們用的是預訓練模型。
總之我們回到代碼部分没佑,向數據中再添加一列毕贼。這個列會包含語義分析,我們可以繪制出 dataframe 查看更新結果:
# 創(chuàng)建包含分析結果的列:data['SA'] = np.array([ analize_sentiment(tweet) for tweet in data['Tweets'] ])# 展示添加新列后的dataframedisplay(data.head(10))
獲取新的輸出:
<img src="https://pic3.zhimg.com/v2-a91f8cf0de2b6de75d1b2b6fd6572f7a_b.jpg" data-caption="" data-size="normal" data-rawwidth="1027" data-rawheight="1695" class="origin_image zh-lightbox-thumb" width="1027" data-original="https://pic3.zhimg.com/v2-a91f8cf0de2b6de75d1b2b6fd6572f7a_r.jpg">
可以看到蛤奢,最后一列包含了語義分析結果(SA)」硌ⅲ現在只需檢查結果。
分析結果
我們以簡單的方式檢查語義分析結果啤贩,分別計算出包含正面情緒待秃、負面情緒和中性情緒的推文,及其比例痹屹。
pos_tweets = [ tweet for index, tweet in enumerate(data['Tweets']) if data['SA'][index] > 0]neu_tweets = [ tweet for index, tweet in enumerate(data['Tweets']) if data['SA'][index] == 0]neg_tweets = [ tweet for index, tweet in enumerate(data['Tweets']) if data['SA'][index] < 0]
現在我們獲得了列表章郁,只需打印出比例:
print("Percentage of positive tweets: {}%".format(len(pos_tweets)*100/len(data['Tweets'])))print("Percentage of neutral tweets: {}%".format(len(neu_tweets)*100/len(data['Tweets'])))print("Percentage de negative tweets: {}%".format(len(neg_tweets)*100/len(data['Tweets'])))
獲得如下結果:
具有正面情緒的推文:51.0%
具有中性情緒的推文:27.0%
具有負面情緒的推文:22.0%
&lt;img src="https://pic2.zhimg.com/v2-e87e903018d10bac0c11703f0e268fd5_b.jpg" data-caption="" data-size="small" data-rawwidth="630" data-rawheight="420" class="origin_image zh-lightbox-thumb" width="630" data-original="https://pic2.zhimg.com/v2-e87e903018d10bac0c11703f0e268fd5_r.jpg"&gt;
不過考慮到我們只收集了特朗普推特賬戶的 200 條推文,如果想獲得更高的準確度痢掠,可以收集更多推文驱犹。
從本文我們可以看到嘲恍,使用 Python 能夠完成提取數據足画、處理數據、可視化數據和分析數據這一套流程佃牛。希望本文能對大家使用 Python 進行文本處理有所幫助淹辞。
本項目代碼地址: