獨家 | 基於NLP的COVID-19虛假新聞檢測(附代碼)

作者:Susan Li

翻譯:楊毅遠

校對:吳金笛

本文長度爲4400字,建議閱讀8分鐘

本文爲大家介紹了基於自然語言處理的COVID-19虛假新聞檢測方法以及可視化方法,並結合真實的新聞數據集與完整的代碼復現了檢測以及可視化的過程。

標籤:自然語言處理 數據可視化

最近有這樣一則新聞:一半的加拿大人被COVID-19的陰謀論所愚弄,這個新聞真的令人心碎。

世界衛生組織(WHO)稱,與COVID-19相關的信息流行病與病毒本身同樣危險。同樣地,陰謀論、神話和誇大的事實可能會產生超出公共健康範圍的後果。

多虧了Lead Stories,Poynter,FactCheck.org,Snopes,EuVsDisinfo等項目可以監視、識別和檢查散佈在世界各地的虛假信息。

爲了探究COVID-19虛假新聞的內容,我對於真實新聞和虛假新聞進行了嚴格的定義。具體來說,真實新聞是衆所周知的真實報道並且來自可信賴的新聞機構;虛假新聞是衆所周知的錯誤報道並且來自知名的有意試圖散佈錯誤信息的虛假新聞網站。

基於以上定義,我從各種新聞資源中收集了1100篇有關COVID-19的新聞文章和社交網絡帖子並對其進行了標記。

數據集可以在這裏找到:

https://raw.githubusercontent.com/susanli2016/NLP-with-Python/master/data/corona_fake.csv

數據

1. from nltk.corpus import stopwords  
2. STOPWORDS = set(stopwords.words('english'))  
3. from sklearn.feature_extraction.text import CountVectorizer  
4.   
5. from textblob import TextBlob  
6. import plotly.express as px  
7. import plotly.figure_factory as ff  
8. import plotly.graph_objects as go  
9.   
10. df = pd.read_csv('data/corona_fake.csv')  
11. df.loc[df['label'] == 'Fake', ['label']] = 'FAKE'  
12. df.loc[df['label'] == 'fake', ['label']] = 'FAKE'  
13. df.loc[df['source'] == 'facebook', ['source']] = 'Facebook'  
14.   
15. df.loc[5]['label'] = 'FAKE'  
16. df.loc[15]['label'] = 'TRUE'  
17. df.loc[43]['label'] = 'FAKE'  
18. df.loc[131]['label'] = 'TRUE'  
19. df.loc[242]['label'] = 'FAKE'  
20.   
21. df = df.sample(frac=1).reset_index(drop=True)  
22. df.label.value_counts()

process_data.py

經過數據清洗,我們可以看到共有586篇真實新聞和578篇虛假新聞。

df.loc[df['label'] == 'TRUE'].source.value_counts()

圖一

真實新聞主要來自哈佛健康出版社(Harvard Health Publishing)、《紐約時報》(The New York Times)、約翰霍普金斯大學彭博公共衛生學院(Johns Hopkins Bloomberg School of Public Health)、世衛組織(WHO)以及疾病預防控制中心(CDC)等機構。

df.loc[df['label'] == 'FAKE'].source.value_counts()

圖二

其中的幾個虛假新聞是從Facebook的帖子中收集的,其是一個名爲Natural News的極右網站和一個名爲orthomolecular.org的替代醫學網站。一些文章或帖子已從互聯網或社交網絡中刪除,但是,他們仍能夠在網絡中被查詢到。

使用下面的函數,我們將能夠閱讀任何給定的新聞內容並由此確定如何清洗它們:

1. def print_plot(index):  
2.     example = df[df.index == index][['text','label']].values[0]  
3.     if len(example) > 0:  
4.         print(example[0])  
5.         print('label:', example[1])  
6.           
7. print_plot(500)

print_plot.py

print_plot(1000)  

由於我們數據集中文章內容很清晰,所以我們僅需要刪除標點符號並將大寫字母改爲小寫即可。

1. df['text'] = df['text'].str.replace('[^\w\s]','')  
2. df['text'] = df['text'].str.lower()

文章長度

在接下來的步驟中:

  • 獲取每篇新聞的情感得分,而且分數控制在[-1,1]範圍內,其中1表示積極情緒,-1表示消極情緒。

  • 獲取每篇文章的長度(字數)。

df['polarity'] = df['text'].map(lambda text: TextBlob(text).sentiment.polarity)  
   
def text_len(x):  
    if type(x) is str:  
             return len(x.split())  
    else:  
        return 0  
   
df['text_len'] = df['text'].apply(text_len)  
nums_text = df.query('text_len > 0')['text_len']  
   
fig = ff.create_distplot(hist_data = [nums_text], group_labels = ['Text'])  
fig.update_layout(title_text='Distribution of article length', template="plotly_white")  
fig.show()  

polarity_length.py

圖三

數據集中的大多數文章少於1000個單詞。不過,有少數文章超過4000個單詞。

當我們按標籤區分時,就文章的長度而言,真實新聞和虛假新聞之間沒有明顯的區別,儘管在數據集中大多數真實新聞似乎都比虛假新聞短一些。

1. fig = px.histogram(df, x="text_len", y="text", color="label",  
2.                    marginal="box",  
3.                    hover_data=df.columns, nbins=100)  
4. fig.update_layout(title_text='Distribution of article length', template="plotly_white")  
5. fig.show()  
text_len_hist.py

 

圖四

爲了顯示不同新聞的文本長度的概率密度,我們使用小提琴圖(violin plot)表示:

1. fig = px.violin(df, y='text_len', color='label',  
2.                 violinmode='overlay',   
3.                 hover_data=df.columns, template='plotly_white')  
4. fig.show()

text_len_violin.py

圖五

  • Facebook vs. Harvard

平均而言,Facebook的帖子比哈佛健康的文章短得多:

1. df_new = df.loc[(df['source'] == 'Facebook') | (df['source'] == 'https://www.health.harvard.edu/')]  
2.   
3. fig = px.histogram(df_new, x="text_len", y="text", color='source',  
4.                    marginal="box",  
5.                    hover_data=df_new.columns, nbins=100)  
6. fig.update_layout(title_text='Distribution of article length of two sources', template="plotly_white")  
7. fig.show()

facebook_harvard_textlen_hist.py

圖六

我們也可以使用小提琴圖(violin plot)來呈現:

1. fig = px.violin(df_new, y='text_len', color='source',  
2.                 violinmode='overlay',   
3.                 hover_data=df_new.columns, template='plotly_white')  
4. fig.show() 

facebook_harvard_textlen_violin.py

 

圖七

 

也許我們大家都很熟悉,Facebook虛假帖子的內容往往更短。發表文章的人試圖通過試探法而非說服力來說服讀者。

  • 情感極性

1. x1 = df.loc[df['label']=='TRUE']['polarity']  
2. x2 = df.loc[df['label'] == 'FAKE']['polarity']  
3.   
4. group_labels = ['TRUE', 'FAKE']  
5.   
6. colors = ['rgb(0, 0, 100)', 'rgb(0, 200, 200)']  
7.   
8. fig = ff.create_distplot(  
9.     [x1, x2], group_labels,colors=colors)  
10.   
11. fig.update_layout(title_text='polarity', template="plotly_white")  
12. fig.show()

label_polarity.py

圖八

真實新聞與虛假新聞在情感方面沒有明顯差異,我們可以使用小提琴圖(violin plot)來證實:

1. fig = p.violin(df, y='polarity', color="label",  
2.                 violinmode='overlay',  
3.                 template='plotly_white')  
4. fig.show()

polarity_violin.py

圖九

當我們比較這四個來源之間的情緒極性時,我們可以看到《紐約時報》和《自然新聞》的情緒分佈比哈佛健康新聞和Facebook的情緒分佈要窄得多。

1. x1 = df.loc[df['source']=='Facebook']['polarity']  
2. x2 = df.loc[df['source'] == 'https://www.health.harvard.edu/']['polarity']  
3. x3 = df.loc[df['source'] == 'https://www.nytimes.com/']['polarity']  
4. x4 = df.loc[df['source'] == 'https://www.naturalnews.com/']['polarity']  
5. group_labels = ['Facebook', 'Harvard', 'nytimes', 'naturalnews']  
6.   
7. colors = ['rgb(0, 0, 100)', 'rgb(0, 200, 200)', 'rgb(100, 0, 0)', 'rgb(200, 0, 200)']  
8.   
9. # Create distplot with custom bin_size  10. fig = ff.create_distplot(  
11.     [x1, x2, x3, x4], group_labels,colors=colors)  
12.   
13. fig.update_layout(title_text='polarity', template="plotly_white")  
14. fig.show()  

polarity_source.py

圖十

這意味着《紐約時報》的新聞和數據中的自然新聞聽起來不那麼具有情緒。

可以用以下小提琴圖(violin plot)來證實:

1. fig = go.Figure()  
2.   
3. sources = ['https://www.health.harvard.edu/', 'https://www.nytimes.com/', 'Facebook', 'https://www.naturalnews.com/']  
4.   
5. for source in sources:  
6.     fig.add_trace(go.Violin(x=df['source'][df['source'] == source],  
7.                             y=df['polarity'][df['source'] == source],  
8.                             name=source,  
9.                             box_visible=True,  
10.                             meanline_visible=True))  
11. fig.update_layout(title_text='Polarity of four sources', template='plotly_white')  
12. fig.show()

source_violin.py

圖十一

  • 情緒vs文章長度vs真實性

我注意到我收集的新聞和帖子既不是非常積極,也不是非常消極。它們大多數處於適度的正數範圍內,並且大多數長度少於1000個字。

1. fig = px.density_contour(df, x='polarity', y='text_len', marginal_x='histogram', marginal_y='histogram', template='plotly_white')  
2. fig.update_layout(title_text='Sentiment vs. Article length')  
3. fig.show()

len_polarity.py

圖十二

情感與文章的長度之間沒有明顯的關係。通常,文章的情感或篇幅不能反映其真實性。虛假新聞與真實新聞之間的區別可能是相當隨意的。

1. fig = px.scatter(df, x='polarity', y='text_len', color='label', template="plotly_white")  
2. fig.update_layout(title_text='Sentiment polarity')  
3. fig.show()

polarity_scatter.py

圖十三

df.groupby(['source']).mean().sort_values('polarity', ascending=False)

圖十四

我注意到魯迪·朱利安妮(Rudy Giuliani)的帖子是情感評分最高的帖子之一,所以我很好奇想知道這篇帖子是關於什麼的:

df.loc[df['source'] == 'RudyGiuliani']['text'][880]

當然是關於羥氯喹(Hydroxychloroquine)的啦~。

真實與虛假新聞的內容

現在,我們將瞭解數據集中包含哪些主題:

1. common_bigram_true = get_top_n_bigram(df.loc[df['label'] == 'TRUE']['text'], 20)  
2. for word, freq in common_bigram_true:  
3.     print(word, freq)

true_bigram.py

1. common_bigram_fake = get_top_n_bigram(df.loc[df['label'] == 'FAKE']['text'], 20)  
2. for word, freq in common_bigram_fake:  
3.     print(word, freq)

fake_bigram.py

  • 促進治癒:這包括使用大劑量靜脈注射維生素C。

  • 關於起源的推測:這個主題包括聲稱冠狀病毒是在用於生物武器的實驗室中製造的,或者是5G技術導致了這種疾病。

  • 關於有影響力人士的謠言:例如比爾·蓋茨和福西博士代表製藥公司策劃了冠狀病毒。

  • 應對人們的恐懼:例如梅林達·蓋茨基金會和約翰·霍普金斯大學在三個月前通過Event 201預測了冠狀病毒。

從我們的數據來看,真實和虛假新聞內容之間的一個明顯區別是,虛假新聞似乎更多地使用了人的名字,這表明虛假新聞可能更加個性化。

naturalnews.com vs orthomolecular.org

以上兩個新聞來源都提倡陰謀論,但是它們卻關注不同的主題。

1. naturalnews_bigram = get_top_n_bigram(df.loc[df['source'] == 'https://www.naturalnews.com/']['text'], 20)  
2. for word, freq in naturalnews_bigram:  
3.     print(word, freq)

natural_bigram.py

naturalnews.com一直在傳播虛假信息,例如在中國實驗室將冠狀病毒設計爲生物武器,並且/或者傳播病毒來掩蓋暴露於5G無線技術有關有害健康的影響。

1. ortho_bigram = get_top_n_bigram(df.loc[df['source'] == 'http://orthomolecular.org/']['text'], 20)  
2. for word, freq in ortho_bigram:  
3.     print(word, freq)

ortho_bigram.py

orthomolecular.org一直在推廣使用大劑量靜脈注射維生素C作爲治療方法,但尚無根據。

根據以上分析,大家可以隨時自行判斷其他新聞的真實性。

總結

首先,我們不知道在收集數據時是否存在選擇偏差。其次,雖然以上的新聞都是用戶參與度很高的新聞,但我們無法說出這些新聞報導產生的實際流量。儘管有這些不足,但此數據集提供了合理的標籤,並且我們知道其內的所有新聞都已被廣泛閱讀和分享。

原文標題:

Explore COVID-19 Infodemic

原文鏈接:

https://towardsdatascience.com/explore-covid-19-infodemic-2d1ceaae2306

編輯:王菁

校對:楊學俊

譯者簡介

楊毅遠,清華大學自動化系研一在讀,本科畢業於華中科技大學自動化學院實驗班,研究方向爲工業過程檢測中的AI算法。喜歡唱歌、喜歡接觸新鮮事物的我對於“AI+”格外感興趣;入門CV和數據挖掘的我,希望接觸到更多非自己研究領域內的事物,拓寬自己的知識圈。

翻譯組招募信息

工作內容:需要一顆細緻的心,將選取好的外文文章翻譯成流暢的中文。如果你是數據科學/統計學/計算機類的留學生,或在海外從事相關工作,或對自己外語水平有信心的朋友歡迎加入翻譯小組。

你能得到:定期的翻譯培訓提高志願者的翻譯水平,提高對於數據科學前沿的認知,海外的朋友可以和國內技術應用發展保持聯繫,THU數據派產學研的背景爲志願者帶來好的發展機遇。

其他福利:來自於名企的數據科學工作者,北大清華以及海外等名校學生他們都將成爲你在翻譯小組的夥伴。

點擊文末“閱讀原文”加入數據派團隊~

轉載須知

如需轉載,請在開篇顯著位置註明作者和出處(轉自:數據派ID:DatapiTHU),並在文章結尾放置數據派醒目二維碼。有原創標識文章,請發送【文章名稱-待授權公衆號名稱及ID】至聯繫郵箱,申請白名單授權並按要求編輯。

發佈後請將鏈接反饋至聯繫郵箱(見下方)。未經許可的轉載以及改編者,我們將依法追究其法律責任。

點擊“閱讀原文”擁抱組織

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章