Python情感分析實戰(zhàn)演練——以特朗普的推文為例

姓名:閆偉? 學號:15020150038

轉載自:https://zhuanlan.zhihu.com/p/47341761

【嵌牛導讀】:自然語言處理專家 Rodolfo Ferro 可以通過Python來對一個人的情感進行分析。

【嵌牛鼻子】:Python Pandas Numpy?

【嵌牛提問】:如何用 Python 完成情感分析

【嵌牛正文】:

在本文我們會學習以下三方面內(nèi)容:

使用 Tweepy 提取 Twitter 數(shù)據(jù),學習如何用 Pandas 處理數(shù)據(jù)

使用 Numpy,Matplotlib 和 Seaborn 完成一些簡單的統(tǒng)計和可視化工作

使用 Textblob 對提取的特朗普的推文進行情感分析

項目代碼地址見文末。

我們需要什么?

首先,我們需要安裝 Python。

我(作者 Rodolfo Ferro——譯者注)使用的是 Python 3.6,不過所有代碼在 Python 2.7 上應該也都能運行。強烈推薦安裝 Anaconda,這是個非常有用的 Python 包管理平臺,內(nèi)置了很多有用的工具,比如 Jupyter Notebooks。我會用 Jupyter Notebook 講解本文的代碼,如果你在用其它的文本編輯器,也能跑一些簡單的腳本,只是需要做些適配(不難)。

我們需要安裝的環(huán)境依賴包括:

Numpy:使用 Python 進行科學計算的基本工具包。此外,Numpy 也可以用作通用數(shù)據(jù)的高效多維容器。

Pandas:開源庫,提供高性能、易于使用的數(shù)據(jù)結構和數(shù)據(jù)分析工具。

Tweepy:一個使用方便的 Python 庫,用于獲取 Twitter API。

Matplotlib:一個 Python 2D 繪圖庫,可生成多種格式的高質量圖形。

Seaborn:基于 matplotlib 的 Python 可視化庫,提供的 API 可繪制美觀的統(tǒng)計圖形。

Textblob:用于執(zhí)行文本數(shù)據(jù)處理的 Python 庫,提供的 API 可執(zhí)行常見的自然語言處理任務。

以上環(huán)境依賴都通過 pip 安裝。待安裝完所有軟件包后,開始寫代碼!

1 提取推特數(shù)據(jù)(Tweepy+Pandas)

導入庫

這一步很簡單,將如下代碼復制到你的 Jupyter Notebook 上就行:

# General:import tweepy? ? ? ? ? # 用來使用推特APIimport pandas as pd? ? # 用來處理數(shù)據(jù)import numpy as np? ? ? # 用來計算數(shù)字# 用來繪圖和可視化from IPython.display import displayimport matplotlib.pyplot as pltimport seaborn as sns%matplotlib inline

很好!下載運行該代碼塊,進入下個部分。

創(chuàng)建一個推特應用

要想提取推文用于分析,我們需要登錄我們的推特開發(fā)者賬號,并創(chuàng)建一個應用。進行這項操作的網(wǎ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)中看不見。現(xiàn)在我們可以使用 Twitter API 了,為此需要創(chuàng)建一個允許我們進行密鑰身份驗證的函數(shù)。我們會在另一個代碼單元中調(diào)用此函數(shù),并運行它:

# 導入訪問密鑰: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

目前為止還是很簡單的,對吧?在下個部分我們開始提取推文。

推文提取

現(xiàn)在,我們創(chuàng)建一個函數(shù)來設置推特 API,可以用該函數(shù)創(chuàng)建一個“extractor”對象。然后我們會使用 Tweepy 的函數(shù) extractor.user_timeline(screen_name, count) 從 screen_name 的用戶中提取 count 數(shù)量的推文。

在文章標題里也說過了,我們本文選擇川普的推文作為素材,從中提取數(shù)據(jù)進行情感分析。沒辦法,誰叫他推特發(fā)的那么頻繁呢。

提取推特數(shù)據(jù)的方法如下:

# 創(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()

有了這個,我們會得到一個與之類似的輸出,并且將該輸出和推特賬號進行比較(用以檢查我們是否保持一致):

提取的推文數(shù)量: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!

現(xiàn)在我們有了提取程序以及提取后的數(shù)據(jù),均位于 tweets 變量中。這里必須說一句,該列表中的每個元素都是一個來自 Tweepy 的 tweet 對象,我們會在下部分學習怎樣處理該數(shù)據(jù)。

創(chuàng)建(Pandas)DataFrame

現(xiàn)在我們用初始信息構造一個 Pandas DataFrame,從而能以很容易的方式處理信息。

Ipython 的 display 函數(shù)會以很淺顯易懂的方式繪制出輸出結果,dataframe 的 head 方法則能讓我們可視化該 dataframe 的前 5 個元素(或作為參數(shù)傳遞的第一個參數(shù))。

所以,使用 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">

現(xiàn)在我們獲得了一個數(shù)據(jù)排列有序的干凈圖表。

一個有趣的地方就是 Tweepy 中 tweets 結構具有的內(nèi)部方法數(shù)量:

# 單個tweet對象中的內(nèi)部方法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']

這里比較有意思的部分就是每條推文中所包含的元數(shù)據(jù)數(shù)量,如果我們想獲取像發(fā)推日期或發(fā)推源這樣的數(shù)據(jù),我們就可以用該屬性獲取信息。下面是一個例子:

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]}]}

現(xiàn)在我們整理相關數(shù)據(jù),并將其添加到我們的dataframe中。

將相關信息添加至Dataframe中

可以看到,我們能從單條推特中獲取很多數(shù)據(jù),但并非所有數(shù)據(jù)都對我們有用。我們這里只需要向 dataframe 中添加部分數(shù)據(jù)。我們會使用 Python 列表表達式,并為 dataframe 添加一個新列,只需在方括號之間添加內(nèi)容名稱并分配內(nèi)容即可。代碼如下:

# 添加相關數(shù)據(jù)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">

現(xiàn)在我們提取出了數(shù)據(jù),也將數(shù)據(jù)進行了整理,方便處理。下面我們進一步處理數(shù)據(jù),可視化一些圖表,并收集一些統(tǒng)計數(shù)據(jù)。本文的第一部分就算完成了。

2 可視化和基本統(tǒng)計

平均值和受歡迎度

我們首先計算一些基本的統(tǒng)計數(shù)據(jù),比如所有推文字符長度的平均值,被點贊和轉發(fā)次數(shù)最多的推文,等等。

現(xiàn)在我們只需在代碼下面添加一些輸入代碼和輸出。

使用 Numpy 獲得平均值:

# 提取長度平均值mean = np.mean(data['len'])print("The lenght's average in tweets: {}".format(mean))

推文的平均長度為:125.925

為了能提取更多數(shù)據(jù),我們使用 Pandas 的一些功能:

# 提取點贊數(shù)和轉發(fā)數(shù)最多的推文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]# 點贊數(shù)最多: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ā)數(shù)最多: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!

點贊數(shù):222205

字數(shù):144

轉發(fā)數(shù)更多的推文是:

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ā)數(shù):66099

字數(shù):144

一個很常見的事就是“點贊數(shù)更多的推文,轉發(fā)數(shù)同樣更多”,不過也不是每回都這樣。我們使用 Numpy 的 max 函數(shù)找出‘likes’列里面的最大點贊數(shù)和‘RTs’中的最大轉發(fā)數(shù),只需尋找兩列中每一列里滿足最大值條件的索引。由于轉發(fā)數(shù)與點贊數(shù)(最大值)相同的推文可能不止一條,我們只需取用找到的第一個結果,所以我們使用 .index[0] 將索引分配給變量 fa 和 rt。要想輸出滿足條件的推文,我們訪問數(shù)據(jù)的方式和訪問矩陣或任何索引對象的方式是一樣的。

下面準備畫點圖。

時序

Pandas 內(nèi)置了用于時序的對象。因為我們有帶有發(fā)推日期的整個向量,所以分別按照推文長度、點贊數(shù)和轉發(fā)數(shù)來構造數(shù)據(jù)的時序。

操作方式為:

# 創(chuàng)建數(shù)據(jù)的時序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">

在同一圖表中繪出點贊數(shù)和轉發(fā)數(shù)對比的方式為:

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ā)推源

本文的第二部分我們就快完成了,現(xiàn)在我們用餅狀圖繪制出發(fā)推設備來源,因為我們發(fā)現(xiàn)并非每條推文都是相同的來源。首先清洗所有來源:

# 獲得所有可能來源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

現(xiàn)在我們計算每個來源的數(shù)量,并為之創(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 庫,可用于處理正則表達式。這里我得分享兩個實用函數(shù):a) 清洗文本(意思是任何與字母數(shù)字值不同的符號將重新映射到滿足此條件的新符號)b) 創(chuàng)建一個分類器,在清洗文本后分析每條推文的歸一性。這里就不再深入解釋每種函數(shù)的具體工作原理了,因為那就扯遠了,看官方文檔應該就明白了:

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

效果應該差不多,因為我們用的是預訓練模型。

總之我們回到代碼部分,向數(shù)據(jù)中再添加一列。這個列會包含語義分析,我們可以繪制出 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)?,F(xiàn)在只需檢查結果。

分析結果

我們以簡單的方式檢查語義分析結果,分別計算出包含正面情緒、負面情緒和中性情緒的推文,及其比例。

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]

現(xiàn)在我們獲得了列表,只需打印出比例:

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%

&amp;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"&amp;gt;

不過考慮到我們只收集了特朗普推特賬戶的 200 條推文,如果想獲得更高的準確度,可以收集更多推文。

從本文我們可以看到,使用 Python 能夠完成提取數(shù)據(jù)、處理數(shù)據(jù)、可視化數(shù)據(jù)和分析數(shù)據(jù)這一套流程。希望本文能對大家使用 Python 進行文本處理有所幫助。

本項目代碼地址:

https://github.com/RodolfoFerro/pandas_twitter

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容