How to build a Chrome Extension to analyze the text as you write

Introduction

Not long ago, I started writing on Medium as a part-time gig to alternate with my freelance work. Not being a native English speaker, I found using chrome extensions like Grammarly really helpful. (In case you don’t know it yet, it is a digital writing tool that uses artificial intelligence and natural language processing to help with grammar checking, spell checking, plagiarism detection and suggestions about clarity, formality, tone, and vocabulary). Anyway, I don’t use all of its features because it has different plans (Free, Premium for individuals and Premium for business) or at least I didn’t have the necessity of using those features yet. So I thought of developing my own chrome extension implementing only the features I need, in order to learn the possibilities this technology offers.

Extensions are not only for Google Chrome though. Other popular browsers like Microsoft Edge and Mozilla Firefox support extensions as well, but extensions are the same for everyone: they are small applications built using HTML, CSS, and JavaScript, packaged in a specific way along with configuration files.

They need to follow the Web Extension API standard, which is supported by Chromium-based browsers such as Google Chrome, Microsoft Edge, Mozilla Firefox, and Microsoft Edge.

What’s a Chrome Extension for?

Chrome extensions are not only for text analysis. They can interact with the tabs of your Chrome browser using permissions, detect URL matches, inject code (HTML, JavaScript, CSS for example), do API calls, and so on.

If we give a look to the Chrome Web Store, we can check all the different categories:

Image for post

Categories on the Chrome Web Store

What are we going to build?

We will build an extension to count words and characters on a text field or input as we type, and to calculate the total of money you will gain (For freelance writers, for example) setting the price per word (PPW). We will call it ChETA, which stands for Chrome Extension for Text Analysis, which in my native Argentina means cool/awesome.

Our extension will look like the following, while opened from the Extensions tab:

Image for post

We will ask the user to locate the input he wants to use. Then, he will need to write _ _(add it anywhere on the input or replacing the content, it’s the same) on it and click Start. Optionally, he will be able to set a price per word (PPW from now on).

For example, on Google’s input:

Image for post

Preview: Before clicking Start on ChETA

And when clicking Start, we will inject into the page HTML code the things we need to start listening inputs change using a floating container:

Image for post

Preview: After clicking Start on ChETA

Extension Architecture

Extensions are made of different components that interacts with each other. Components can include background scriptscontent scripts, an options pageUI elements, and various logic files. Extensions components are created with web development technologies: HTML, CSS, and JavaScript. An extension’s components will depend on its functionality and may not require every option.

  1. manifest.json: Describes what’s in the source package. It defines where the browser could find the background, content script, popup, and options pages. It also describes the permissions required by the extension (For example to allow the extension to check all tabs, only current tab, use storage, and so on)
  2. background.js: A script or piece of code that is launched when the extension starts, and won’t be terminated until the extension is removed or the browser shutdowns. This file has access to all chrome APIs, and other parts are limited to it. This script does not include a UI and does not have access to the DOM.
  3. popup.html: The UI which is displayed when the user clicks on ‘Browser Action’, which is the button right to the browser address bar where the extensions are located. Most extensions need a popup as entry, but they can also be developed to be called using right-click on pages.
  4. options: It’s an optional part of the extension, which not all extensions include. It is used as a configuration UI for the extension, in order to enable multiple views.
  5. content script: A script or piece of code that runs in a tab with a specific URL pattern, defined in manifest.json. If the URL matches with the manifest description, the browser will launch the content script. It will be terminated when the URL changes or when the tab closes. It is needed to manipulate the DOM.
  6. URL matching can be useful when we need to launch our script on specific URLs or specific instances of a web flow.

For this tutorial, we will use React.js to build the extension. The source code is available on Github (https://github.com/juancurti/cheta-extension) to follow along.

Let’s build the extension

First, we will create the react app and remove unnecessary files we won’t use:

npx create-react-app cheta-extension
cd cheta-extension/
cd src/
rm -rf setupTests.js serviceWorker.js logo.svg index.css App.test.js App.js App.css

We will install node-sass, which is not mandatory but it will help us write quicker CSS code:

npm i node-sass — save

Now we will replace the manifest.json located in the **public/ **folder, which is related to React.js, for the following code corresponding to the manifest.json concept explained above:

{
 “name”: “ChETA: Chrome Extension for Text Analysis”,
 “version”: “1.0.0”,
 “manifest_version”: 2,
 “description”: “ChETA: Chrome Extension for Text Analysis”,
 “icons”: {
 “512”: “logo512.png”
 },
 “permissions”: [“activeTab”],
 “browser_action”: {
 “default_icon”: “logo512.png”,
 “default_popup”: “popup.html”
 }
}

_Note: The logo512.png file can be found on the repository: _Link here

As explained before, the initial point of a Chrome Extension should be a popup.html, so we will create a build script to rename our index.html generated by React build to popup.html.

#programming #software-development #productivity #google #react

What is GEEK

Buddha Community

How to build a Chrome Extension to analyze the text as you write

Navigating Between DOM Nodes in JavaScript

In the previous chapters you've learnt how to select individual elements on a web page. But there are many occasions where you need to access a child, parent or ancestor element. See the JavaScript DOM nodes chapter to understand the logical relationships between the nodes in a DOM tree.

DOM node provides several properties and methods that allow you to navigate or traverse through the tree structure of the DOM and make changes very easily. In the following section we will learn how to navigate up, down, and sideways in the DOM tree using JavaScript.

Accessing the Child Nodes

You can use the firstChild and lastChild properties of the DOM node to access the first and last direct child node of a node, respectively. If the node doesn't have any child element, it returns null.

Example

<div id="main">
    <h1 id="title">My Heading</h1>
    <p id="hint"><span>This is some text.</span></p>
</div>

<script>
var main = document.getElementById("main");
console.log(main.firstChild.nodeName); // Prints: #text

var hint = document.getElementById("hint");
console.log(hint.firstChild.nodeName); // Prints: SPAN
</script>

Note: The nodeName is a read-only property that returns the name of the current node as a string. For example, it returns the tag name for element node, #text for text node, #comment for comment node, #document for document node, and so on.

If you notice the above example, the nodeName of the first-child node of the main DIV element returns #text instead of H1. Because, whitespace such as spaces, tabs, newlines, etc. are valid characters and they form #text nodes and become a part of the DOM tree. Therefore, since the <div> tag contains a newline before the <h1> tag, so it will create a #text node.

To avoid the issue with firstChild and lastChild returning #text or #comment nodes, you could alternatively use the firstElementChild and lastElementChild properties to return only the first and last element node, respectively. But, it will not work in IE 9 and earlier.

Example

<div id="main">
    <h1 id="title">My Heading</h1>
    <p id="hint"><span>This is some text.</span></p>
</div>

<script>
var main = document.getElementById("main");
alert(main.firstElementChild.nodeName); // Outputs: H1
main.firstElementChild.style.color = "red";

var hint = document.getElementById("hint");
alert(hint.firstElementChild.nodeName); // Outputs: SPAN
hint.firstElementChild.style.color = "blue";
</script>

Similarly, you can use the childNodes property to access all child nodes of a given element, where the first child node is assigned index 0. Here's an example:

Example

<div id="main">
    <h1 id="title">My Heading</h1>
    <p id="hint"><span>This is some text.</span></p>
</div>

<script>
var main = document.getElementById("main");

// First check that the element has child nodes 
if(main.hasChildNodes()) {
    var nodes = main.childNodes;
    
    // Loop through node list and display node name
    for(var i = 0; i < nodes.length; i++) {
        alert(nodes[i].nodeName);
    }
}
</script>

The childNodes returns all child nodes, including non-element nodes like text and comment nodes. To get a collection of only elements, use children property instead.

Example

<div id="main">
    <h1 id="title">My Heading</h1>
    <p id="hint"><span>This is some text.</span></p>
</div>

<script>
var main = document.getElementById("main");

// First check that the element has child nodes 
if(main.hasChildNodes()) {
    var nodes = main.children;
    
    // Loop through node list and display node name
    for(var i = 0; i < nodes.length; i++) {
        alert(nodes[i].nodeName);
    }
}
</script>

#javascript 

OpenCV putText() - Writing Text on Images

Hello fellow learner! In this tutorial, we will learn how to write string text on Images in Python using the OpenCV putText() method. So let’s get started.

Table of Contents

What is the OpenCV putText() method?

OpenCV Python is a library of programming functions mainly aimed at real-time computer vision and image processing problems.

OpenCV contains putText() method which is used to put text on any image. The method uses following parameters.

  • img: The Image on which you want to write the text.
  • text: The text you want to write on the image.
  • org: It is the coordinates of the Bottom-Left corner of your text. It is represented as a tuple of 2 values (X, Y). X represents the distance from the left edge and Y represents the distance from the top edge of the image.
  • fontFace: It denotes the type of font you want to use. OpenCV supports only a subset of Hershey Fonts.
  • FONT_HERSHEY_SIMPLEX
  • FONT_HERSHEY_PLAIN
  • FONT_HERSHEY_DUPLEX
  • FONT_HERSHEY_COMPLEX
  • FONT_HERSHEY_TRIPLEX
  • FONT_HERSHEY_COMPLEX_SMALL
  • FONT_HERSHEY_SCRIPT_SIMPLEX
  • FONT_HERSHEY_SCRIPT_COMPLEX
  • FONT_ITALIC
  • fontScale: It is used to increase/decrease the size of your text. The font scale factor is multiplied by the font-specific base size.
  • color: It represents the color of the text that you want to give. It takes the value in BGR format, i.e., first blue color value, then green color value, and the red color value all in range 0 to 255.
  • thickness (Optional): It represents the thickness of the lines used to draw a text. The default value is 1.
  • lineType (Optional): It denotes the type of line you want to use. 4 LineTypes available are
  • FILLED
  • LINE_4
  • LINE_8 (Default)
  • LINE_AA
  • bottomLeftOrigin (Optional): When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner. The default value is False.

#python modules #opencv #opencv puttext() #writing text on images #opencv puttext() - writing text on images #puttext() - writing text

Arvel  Miller

Arvel Miller

1622258742

9 Chrome Extensions To Make Your Life Easier

It’s 2021 and I am brought here some fresh new chrome extensions. And no, I will not be covering popular ones like Grammarly, uBlock Origin, Dark Reader, etc.

#chrome-extension #google-chrome #chrome #web-development #developer

CODE VN

CODE VN

1646025910

Xây Dựng Một Máy Phát Hiện Tin Tức Giả Mạo Bằng Python

Khám phá tập dữ liệu tin tức giả, thực hiện phân tích dữ liệu chẳng hạn như đám mây từ và ngram, đồng thời tinh chỉnh máy biến áp BERT để xây dựng bộ phát hiện tin tức giả bằng Python bằng cách sử dụng thư viện máy biến áp.

Tin tức giả là việc cố ý phát đi các tuyên bố sai sự thật hoặc gây hiểu lầm như một tin tức, trong đó các tuyên bố là cố ý lừa dối.

Báo chí, báo lá cải và tạp chí đã được thay thế bởi các nền tảng tin tức kỹ thuật số, blog, nguồn cấp dữ liệu truyền thông xã hội và rất nhiều ứng dụng tin tức di động. Các tổ chức tin tức được hưởng lợi từ việc tăng cường sử dụng mạng xã hội và các nền tảng di động bằng cách cung cấp cho người đăng ký thông tin cập nhật từng phút.

Người tiêu dùng hiện có thể truy cập ngay vào những tin tức mới nhất. Các nền tảng truyền thông kỹ thuật số này ngày càng nổi tiếng do khả năng kết nối dễ dàng với phần còn lại của thế giới và cho phép người dùng thảo luận, chia sẻ ý tưởng và tranh luận về các chủ đề như dân chủ, giáo dục, y tế, nghiên cứu và lịch sử. Các mục tin tức giả mạo trên các nền tảng kỹ thuật số ngày càng phổ biến và được sử dụng để thu lợi nhuận, chẳng hạn như lợi ích chính trị và tài chính.

Vấn đề này lớn đến mức nào?

Bởi vì Internet, phương tiện truyền thông xã hội và các nền tảng kỹ thuật số được sử dụng rộng rãi, bất kỳ ai cũng có thể tuyên truyền thông tin không chính xác và thiên vị. Gần như không thể ngăn chặn sự lan truyền của tin tức giả mạo. Có một sự gia tăng đáng kể trong việc phát tán tin tức sai lệch, không chỉ giới hạn trong một lĩnh vực như chính trị mà bao gồm thể thao, sức khỏe, lịch sử, giải trí, khoa học và nghiên cứu.

Giải pháp

Điều quan trọng là phải nhận biết và phân biệt giữa tin tức sai và tin tức chính xác. Một phương pháp là nhờ một chuyên gia quyết định và kiểm tra thực tế mọi thông tin, nhưng điều này cần thời gian và cần chuyên môn không thể chia sẻ được. Thứ hai, chúng ta có thể sử dụng các công cụ học máy và trí tuệ nhân tạo để tự động hóa việc xác định tin tức giả mạo.

Thông tin tin tức trực tuyến bao gồm nhiều dữ liệu định dạng phi cấu trúc khác nhau (chẳng hạn như tài liệu, video và âm thanh), nhưng chúng tôi sẽ tập trung vào tin tức định dạng văn bản ở đây. Với tiến bộ của học máyxử lý ngôn ngữ tự nhiên , giờ đây chúng ta có thể nhận ra đặc điểm gây hiểu lầm và sai của một bài báo hoặc câu lệnh.

Một số nghiên cứu và thử nghiệm đang được tiến hành để phát hiện tin tức giả trên tất cả các phương tiện.

Mục tiêu chính của chúng tôi trong hướng dẫn này là:

  • Khám phá và phân tích tập dữ liệu Tin tức giả mạo.
  • Xây dựng một công cụ phân loại có thể phân biệt tin tức Giả với độ chính xác cao nhất có thể.

Đây là bảng nội dung:

  • Giới thiệu
  • Vấn đề này lớn đến mức nào?
  • Giải pháp
  • Khám phá dữ liệu
    • Phân phối các lớp học
  • Làm sạch dữ liệu để phân tích
  • Phân tích dữ liệu khám phá
    • Đám mây một từ
    • Bigram thường xuyên nhất (Kết hợp hai từ)
    • Hình bát quái thường gặp nhất (Kết hợp ba từ)
  • Xây dựng Bộ phân loại bằng cách tinh chỉnh BERT
    • Chuẩn bị dữ liệu
    • Mã hóa tập dữ liệu
    • Tải và tinh chỉnh mô hình
    • Đánh giá mô hình
  • Phụ lục: Tạo tệp đệ trình cho Kaggle
  • Phần kết luận

Khám phá dữ liệu

Trong công việc này, chúng tôi đã sử dụng tập dữ liệu tin tức giả từ Kaggle để phân loại các bài báo không đáng tin cậy là tin giả. Chúng tôi có một tập dữ liệu đào tạo hoàn chỉnh chứa các đặc điểm sau:

  • id: id duy nhất cho một bài báo
  • title: tiêu đề của một bài báo
  • author: tác giả của bài báo
  • text: văn bản của bài báo; có thể không đầy đủ
  • label: nhãn đánh dấu bài viết có khả năng không đáng tin cậy được ký hiệu bằng 1 (không đáng tin cậy hoặc giả mạo) hoặc 0 (đáng tin cậy).

Đó là một bài toán phân loại nhị phân, trong đó chúng ta phải dự đoán xem một câu chuyện tin tức cụ thể có đáng tin cậy hay không.

Nếu bạn có tài khoản Kaggle, bạn có thể chỉ cần tải xuống bộ dữ liệu từ trang web ở đó và giải nén tệp ZIP.

Tôi cũng đã tải tập dữ liệu lên Google Drive và bạn có thể tải tập dữ liệu đó tại đây hoặc sử dụng gdownthư viện để tự động tải xuống tập dữ liệu trong sổ ghi chép Google Colab hoặc Jupyter:

$ pip install gdown
# download from Google Drive
$ gdown "https://drive.google.com/uc?id=178f_VkNxccNidap-5-uffXUW475pAuPy&confirm=t"
Downloading...
From: https://drive.google.com/uc?id=178f_VkNxccNidap-5-uffXUW475pAuPy&confirm=t
To: /content/fake-news.zip
100% 48.7M/48.7M [00:00<00:00, 74.6MB/s]

Giải nén các tệp:

$ unzip fake-news.zip

Ba tệp sẽ xuất hiện trong thư mục làm việc hiện tại:, và train.csv, chúng tôi sẽ sử dụng trong hầu hết các hướng dẫn.test.csvsubmit.csvtrain.csv

Cài đặt các phụ thuộc bắt buộc:

$ pip install transformers nltk pandas numpy matplotlib seaborn wordcloud

Lưu ý: Nếu bạn đang ở trong môi trường cục bộ, hãy đảm bảo rằng bạn cài đặt PyTorch cho GPU, hãy truy cập trang này để cài đặt đúng cách.

Hãy nhập các thư viện cần thiết để phân tích:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

Kho tập tin NLTK và mô-đun phải được cài đặt bằng trình tải xuống NLTK tiêu chuẩn:

import nltk
nltk.download('stopwords')
nltk.download('wordnet')

Tập dữ liệu tin tức giả bao gồm các tiêu đề và văn bản bài báo gốc và hư cấu của nhiều tác giả khác nhau. Hãy nhập tập dữ liệu của chúng tôi:

# load the dataset
news_d = pd.read_csv("train.csv")
print("Shape of News data:", news_d.shape)
print("News data columns", news_d.columns)

Đầu ra:

 Shape of News data: (20800, 5)
 News data columns Index(['id', 'title', 'author', 'text', 'label'], dtype='object')

Đây là giao diện của tập dữ liệu:

# by using df.head(), we can immediately familiarize ourselves with the dataset. 
news_d.head()

Đầu ra:

id	title	author	text	label
0	0	House Dem Aide: We Didn’t Even See Comey’s Let...	Darrell Lucus	House Dem Aide: We Didn’t Even See Comey’s Let...	1
1	1	FLYNN: Hillary Clinton, Big Woman on Campus - ...	Daniel J. Flynn	Ever get the feeling your life circles the rou...	0
2	2	Why the Truth Might Get You Fired	Consortiumnews.com	Why the Truth Might Get You Fired October 29, ...	1
3	3	15 Civilians Killed In Single US Airstrike Hav...	Jessica Purkiss	Videos 15 Civilians Killed In Single US Airstr...	1
4	4	Iranian woman jailed for fictional unpublished...	Howard Portnoy	Print \nAn Iranian woman has been sentenced to...	1

Chúng tôi có 20.800 hàng, có năm cột. Hãy cùng xem một số thống kê của chuyên textmục:

#Text Word startistics: min.mean, max and interquartile range

txt_length = news_d.text.str.split().str.len()
txt_length.describe()

Đầu ra:

count    20761.000000
mean       760.308126
std        869.525988
min          0.000000
25%        269.000000
50%        556.000000
75%       1052.000000
max      24234.000000
Name: text, dtype: float64

Số liệu thống kê cho titlecột:

#Title statistics 

title_length = news_d.title.str.split().str.len()
title_length.describe()

Đầu ra:

count    20242.000000
mean        12.420709
std          4.098735
min          1.000000
25%         10.000000
50%         13.000000
75%         15.000000
max         72.000000
Name: title, dtype: float64

Số liệu thống kê cho các tập huấn luyện và kiểm tra như sau:

  • Thuộc texttính có số từ cao hơn với trung bình 760 từ và 75% có hơn 1000 từ.
  • Thuộc titletính là một câu lệnh ngắn với trung bình 12 từ và 75% trong số đó là khoảng 15 từ.

Thử nghiệm của chúng tôi sẽ kết hợp cả văn bản và tiêu đề.

Phân phối các lớp học

Đếm các ô cho cả hai nhãn:

sns.countplot(x="label", data=news_d);
print("1: Unreliable")
print("0: Reliable")
print("Distribution of labels:")
print(news_d.label.value_counts());

Đầu ra:

1: Unreliable
0: Reliable
Distribution of labels:
1    10413
0    10387
Name: label, dtype: int64

Phân phối nhãn

print(round(news_d.label.value_counts(normalize=True),2)*100);

Đầu ra:

1    50.0
0    50.0
Name: label, dtype: float64

Số lượng bài báo không đáng tin cậy (giả mạo hoặc 1) là 10413, trong khi số bài báo đáng tin cậy (đáng tin cậy hoặc 0) là 10387. Gần 50% số bài báo là giả mạo. Do đó, chỉ số độ chính xác sẽ đo lường mức độ hoạt động của mô hình của chúng tôi khi xây dựng bộ phân loại.

Làm sạch dữ liệu để phân tích

Trong phần này, chúng tôi sẽ làm sạch tập dữ liệu của mình để thực hiện một số phân tích:

  • Bỏ các hàng và cột không sử dụng.
  • Thực hiện gán giá trị null.
  • Loại bỏ các ký tự đặc biệt.
  • Loại bỏ các từ dừng.
# Constants that are used to sanitize the datasets 

column_n = ['id', 'title', 'author', 'text', 'label']
remove_c = ['id','author']
categorical_features = []
target_col = ['label']
text_f = ['title', 'text']
# Clean Datasets
import nltk
from nltk.corpus import stopwords
import re
from nltk.stem.porter import PorterStemmer
from collections import Counter

ps = PorterStemmer()
wnl = nltk.stem.WordNetLemmatizer()

stop_words = stopwords.words('english')
stopwords_dict = Counter(stop_words)

# Removed unused clumns
def remove_unused_c(df,column_n=remove_c):
    df = df.drop(column_n,axis=1)
    return df

# Impute null values with None
def null_process(feature_df):
    for col in text_f:
        feature_df.loc[feature_df[col].isnull(), col] = "None"
    return feature_df

def clean_dataset(df):
    # remove unused column
    df = remove_unused_c(df)
    #impute null values
    df = null_process(df)
    return df

# Cleaning text from unused characters
def clean_text(text):
    text = str(text).replace(r'http[\w:/\.]+', ' ')  # removing urls
    text = str(text).replace(r'[^\.\w\s]', ' ')  # remove everything but characters and punctuation
    text = str(text).replace('[^a-zA-Z]', ' ')
    text = str(text).replace(r'\s\s+', ' ')
    text = text.lower().strip()
    #text = ' '.join(text)    
    return text

## Nltk Preprocessing include:
# Stop words, Stemming and Lemmetization
# For our project we use only Stop word removal
def nltk_preprocess(text):
    text = clean_text(text)
    wordlist = re.sub(r'[^\w\s]', '', text).split()
    #text = ' '.join([word for word in wordlist if word not in stopwords_dict])
    #text = [ps.stem(word) for word in wordlist if not word in stopwords_dict]
    text = ' '.join([wnl.lemmatize(word) for word in wordlist if word not in stopwords_dict])
    return  text

Trong khối mã trên:

  • Chúng tôi đã nhập NLTK, đây là một nền tảng nổi tiếng để phát triển các ứng dụng Python tương tác với ngôn ngữ của con người. Tiếp theo, chúng tôi nhập recho regex.
  • Chúng tôi nhập các từ dừng từ nltk.corpus. Khi làm việc với các từ, đặc biệt là khi xem xét ngữ nghĩa, đôi khi chúng ta cần loại bỏ các từ phổ biến không bổ sung bất kỳ ý nghĩa quan trọng nào cho một câu lệnh, chẳng hạn như "but",, v.v."can""we"
  • PorterStemmerđược sử dụng để thực hiện các từ gốc với NLTK. Các gốc từ loại bỏ các phụ tố hình thái của các từ, chỉ để lại phần gốc của từ.
  • Chúng tôi nhập WordNetLemmatizer()từ thư viện NLTK để lemmatization. Lemmatization hiệu quả hơn nhiều so với việc chiết cành . Nó vượt ra ngoài việc rút gọn từ và đánh giá toàn bộ từ vựng của một ngôn ngữ để áp dụng phân tích hình thái học cho các từ, với mục tiêu chỉ loại bỏ các kết thúc không theo chiều hướng và trả lại dạng cơ sở hoặc dạng từ điển của một từ, được gọi là bổ đề.
  • stopwords.words('english')cho phép chúng tôi xem danh sách tất cả các từ dừng tiếng Anh được NLTK hỗ trợ.
  • remove_unused_c()được sử dụng để loại bỏ các cột không sử dụng.
  • Chúng tôi áp đặt giá trị null bằng Nonecách sử dụng null_process()hàm.
  • Bên trong hàm clean_dataset(), chúng ta gọi remove_unused_c()null_process()hàm. Chức năng này có nhiệm vụ làm sạch dữ liệu.
  • Để làm sạch văn bản khỏi các ký tự không sử dụng, chúng tôi đã tạo clean_text()hàm.
  • Đối với xử lý trước, chúng tôi sẽ chỉ sử dụng loại bỏ từ dừng. Chúng tôi đã tạo ra nltk_preprocess()chức năng cho mục đích đó.

Tiền xử lý texttitle:

# Perform data cleaning on train and test dataset by calling clean_dataset function
df = clean_dataset(news_d)
# apply preprocessing on text through apply method by calling the function nltk_preprocess
df["text"] = df.text.apply(nltk_preprocess)
# apply preprocessing on title through apply method by calling the function nltk_preprocess
df["title"] = df.title.apply(nltk_preprocess)
# Dataset after cleaning and preprocessing step
df.head()

Đầu ra:

title	text	label
0	house dem aide didnt even see comeys letter ja...	house dem aide didnt even see comeys letter ja...	1
1	flynn hillary clinton big woman campus breitbart	ever get feeling life circle roundabout rather...	0
2	truth might get fired	truth might get fired october 29 2016 tension ...	1
3	15 civilian killed single u airstrike identified	video 15 civilian killed single u airstrike id...	1
4	iranian woman jailed fictional unpublished sto...	print iranian woman sentenced six year prison ...	1

Phân tích dữ liệu khám phá

Trong phần này, chúng tôi sẽ thực hiện:

  • Phân tích đơn biến : Nó là một phân tích thống kê của văn bản. Chúng tôi sẽ sử dụng đám mây từ cho mục đích đó. Đám mây từ là một cách tiếp cận trực quan hóa cho dữ liệu văn bản trong đó thuật ngữ phổ biến nhất được trình bày ở kích thước phông chữ đáng kể nhất.
  • Phân tích Bivariate: Bigram và Trigram sẽ được sử dụng ở đây. Theo Wikipedia: " n-gram là một chuỗi n mục liền nhau từ một mẫu văn bản hoặc lời nói nhất định. Theo ứng dụng, các mục có thể là âm vị, âm tiết, chữ cái, từ hoặc các cặp cơ sở. N-gram thường được thu thập từ một văn bản hoặc ngữ liệu lời nói ".

Đám mây một từ

Các từ phổ biến nhất xuất hiện ở phông chữ đậm và lớn hơn trong đám mây từ. Phần này sẽ thực hiện một đám mây từ cho tất cả các từ trong tập dữ liệu.

Chức năng của thư viện WordCloudwordcloud() sẽ được sử dụng và generate()được sử dụng để tạo hình ảnh đám mây từ:

from wordcloud import WordCloud, STOPWORDS
import matplotlib.pyplot as plt

# initialize the word cloud
wordcloud = WordCloud( background_color='black', width=800, height=600)
# generate the word cloud by passing the corpus
text_cloud = wordcloud.generate(' '.join(df['text']))
# plotting the word cloud
plt.figure(figsize=(20,30))
plt.imshow(text_cloud)
plt.axis('off')
plt.show()

Đầu ra:

WordCloud cho toàn bộ dữ liệu tin tức giả mạo

Đám mây từ chỉ dành cho tin tức đáng tin cậy:

true_n = ' '.join(df[df['label']==0]['text']) 
wc = wordcloud.generate(true_n)
plt.figure(figsize=(20,30))
plt.imshow(wc)
plt.axis('off')
plt.show()

Đầu ra:

Word Cloud cho tin tức đáng tin cậy

Word cloud chỉ dành cho tin tức giả mạo:

fake_n = ' '.join(df[df['label']==1]['text'])
wc= wordcloud.generate(fake_n)
plt.figure(figsize=(20,30))
plt.imshow(wc)
plt.axis('off')
plt.show()

Đầu ra:

Word Cloud cho tin tức giả mạo

Bigram thường xuyên nhất (Kết hợp hai từ)

N-gram là một chuỗi các chữ cái hoặc từ. Một ký tự unigram được tạo thành từ một ký tự duy nhất, trong khi một bigram bao gồm một chuỗi hai ký tự. Tương tự, từ N-gram được tạo thành từ một chuỗi n từ. Từ "thống nhất" là 1 gam (unigram). Sự kết hợp của các từ "bang thống nhất" là 2 gam (bigram), "thành phố new york" là 3 gam.

Hãy vẽ biểu đồ phổ biến nhất trên tin tức đáng tin cậy:

def plot_top_ngrams(corpus, title, ylabel, xlabel="Number of Occurences", n=2):
  """Utility function to plot top n-grams"""
  true_b = (pd.Series(nltk.ngrams(corpus.split(), n)).value_counts())[:20]
  true_b.sort_values().plot.barh(color='blue', width=.9, figsize=(12, 8))
  plt.title(title)
  plt.ylabel(ylabel)
  plt.xlabel(xlabel)
  plt.show()
plot_top_ngrams(true_n, 'Top 20 Frequently Occuring True news Bigrams', "Bigram", n=2)

Bigram hàng đầu về tin tức giả mạo

Biểu đồ phổ biến nhất về tin tức giả:

plot_top_ngrams(fake_n, 'Top 20 Frequently Occuring Fake news Bigrams', "Bigram", n=2)

Bigram hàng đầu về tin tức giả mạo

Hình bát quái thường gặp nhất (kết hợp ba từ)

Hình bát quái phổ biến nhất trên các tin tức đáng tin cậy:

plot_top_ngrams(true_n, 'Top 20 Frequently Occuring True news Trigrams', "Trigrams", n=3)

Bát quái phổ biến nhất về tin tức giả mạo

Đối với tin tức giả mạo bây giờ:

plot_top_ngrams(fake_n, 'Top 20 Frequently Occuring Fake news Trigrams', "Trigrams", n=3)

Hình bát quái phổ biến nhất trên tin tức giả mạo

Các biểu đồ trên cho chúng ta một số ý tưởng về giao diện của cả hai lớp. Trong phần tiếp theo, chúng ta sẽ sử dụng thư viện máy biến áp để xây dựng công cụ phát hiện tin tức giả.

Xây dựng Bộ phân loại bằng cách tinh chỉnh BERT

Phần này sẽ lấy mã rộng rãi từ hướng dẫn tinh chỉnh BERT để tạo bộ phân loại tin tức giả bằng cách sử dụng thư viện máy biến áp. Vì vậy, để biết thêm thông tin chi tiết, bạn có thể xem hướng dẫn ban đầu .

Nếu bạn không cài đặt máy biến áp, bạn phải:

$ pip install transformers

Hãy nhập các thư viện cần thiết:

import torch
from transformers.file_utils import is_tf_available, is_torch_available, is_torch_tpu_available
from transformers import BertTokenizerFast, BertForSequenceClassification
from transformers import Trainer, TrainingArguments
import numpy as np
from sklearn.model_selection import train_test_split

import random

Chúng tôi muốn làm cho kết quả của chúng tôi có thể tái tạo ngay cả khi chúng tôi khởi động lại môi trường của mình:

def set_seed(seed: int):
    """
    Helper function for reproducible behavior to set the seed in ``random``, ``numpy``, ``torch`` and/or ``tf`` (if
    installed).

    Args:
        seed (:obj:`int`): The seed to set.
    """
    random.seed(seed)
    np.random.seed(seed)
    if is_torch_available():
        torch.manual_seed(seed)
        torch.cuda.manual_seed_all(seed)
        # ^^ safe to call this function even if cuda is not available
    if is_tf_available():
        import tensorflow as tf

        tf.random.set_seed(seed)

set_seed(1)

Mô hình chúng tôi sẽ sử dụng là bert-base-uncased:

# the model we gonna train, base uncased BERT
# check text classification models here: https://huggingface.co/models?filter=text-classification
model_name = "bert-base-uncased"
# max sequence length for each document/sentence sample
max_length = 512

Đang tải tokenizer:

# load the tokenizer
tokenizer = BertTokenizerFast.from_pretrained(model_name, do_lower_case=True)

Chuẩn bị dữ liệu

Bây giờ chúng ta hãy làm sạch NaNcác giá trị khỏi textauthorcác titlecột:

news_df = news_d[news_d['text'].notna()]
news_df = news_df[news_df["author"].notna()]
news_df = news_df[news_df["title"].notna()]

Tiếp theo, tạo một hàm lấy tập dữ liệu làm khung dữ liệu Pandas và trả về phần tách dòng / xác thực của văn bản và nhãn dưới dạng danh sách:

def prepare_data(df, test_size=0.2, include_title=True, include_author=True):
  texts = []
  labels = []
  for i in range(len(df)):
    text = df["text"].iloc[i]
    label = df["label"].iloc[i]
    if include_title:
      text = df["title"].iloc[i] + " - " + text
    if include_author:
      text = df["author"].iloc[i] + " : " + text
    if text and label in [0, 1]:
      texts.append(text)
      labels.append(label)
  return train_test_split(texts, labels, test_size=test_size)

train_texts, valid_texts, train_labels, valid_labels = prepare_data(news_df)

Hàm trên nhận tập dữ liệu trong một kiểu khung dữ liệu và trả về chúng dưới dạng danh sách được chia thành các tập hợp lệ và huấn luyện. Đặt include_titlethành Truecó nghĩa là chúng tôi thêm titlecột vào mục textchúng tôi sẽ sử dụng để đào tạo, đặt include_authorthành Truecó nghĩa là chúng tôi cũng thêm authorvào văn bản.

Hãy đảm bảo rằng các nhãn và văn bản có cùng độ dài:

print(len(train_texts), len(train_labels))
print(len(valid_texts), len(valid_labels))

Đầu ra:

14628 14628
3657 3657

Mã hóa tập dữ liệu

Hãy sử dụng trình mã hóa BERT để mã hóa tập dữ liệu của chúng ta:

# tokenize the dataset, truncate when passed `max_length`, 
# and pad with 0's when less than `max_length`
train_encodings = tokenizer(train_texts, truncation=True, padding=True, max_length=max_length)
valid_encodings = tokenizer(valid_texts, truncation=True, padding=True, max_length=max_length)

Chuyển đổi các mã hóa thành tập dữ liệu PyTorch:

class NewsGroupsDataset(torch.utils.data.Dataset):
    def __init__(self, encodings, labels):
        self.encodings = encodings
        self.labels = labels

    def __getitem__(self, idx):
        item = {k: torch.tensor(v[idx]) for k, v in self.encodings.items()}
        item["labels"] = torch.tensor([self.labels[idx]])
        return item

    def __len__(self):
        return len(self.labels)

# convert our tokenized data into a torch Dataset
train_dataset = NewsGroupsDataset(train_encodings, train_labels)
valid_dataset = NewsGroupsDataset(valid_encodings, valid_labels)

Tải và tinh chỉnh mô hình

Chúng tôi sẽ sử dụng BertForSequenceClassificationđể tải mô hình máy biến áp BERT của chúng tôi:

# load the model
model = BertForSequenceClassification.from_pretrained(model_name, num_labels=2)

Chúng tôi đặt num_labelsthành 2 vì đó là phân loại nhị phân. Hàm dưới đây là một lệnh gọi lại để tính độ chính xác trên mỗi bước xác thực:

from sklearn.metrics import accuracy_score

def compute_metrics(pred):
  labels = pred.label_ids
  preds = pred.predictions.argmax(-1)
  # calculate accuracy using sklearn's function
  acc = accuracy_score(labels, preds)
  return {
      'accuracy': acc,
  }

Hãy khởi tạo các tham số huấn luyện:

training_args = TrainingArguments(
    output_dir='./results',          # output directory
    num_train_epochs=1,              # total number of training epochs
    per_device_train_batch_size=10,  # batch size per device during training
    per_device_eval_batch_size=20,   # batch size for evaluation
    warmup_steps=100,                # number of warmup steps for learning rate scheduler
    logging_dir='./logs',            # directory for storing logs
    load_best_model_at_end=True,     # load the best model when finished training (default metric is loss)
    # but you can specify `metric_for_best_model` argument to change to accuracy or other metric
    logging_steps=200,               # log & save weights each logging_steps
    save_steps=200,
    evaluation_strategy="steps",     # evaluate each `logging_steps`
)

Tôi đã đặt thành per_device_train_batch_size10, nhưng bạn nên đặt nó cao nhất có thể phù hợp với GPU của bạn. Đặt logging_stepssave_stepsthành 200, nghĩa là chúng ta sẽ thực hiện đánh giá và lưu trọng số của mô hình trên mỗi 200 bước huấn luyện.

Bạn có thể kiểm tra  trang này  để biết thêm thông tin chi tiết về các thông số đào tạo có sẵn.

Hãy khởi tạo trình huấn luyện:

trainer = Trainer(
    model=model,                         # the instantiated Transformers model to be trained
    args=training_args,                  # training arguments, defined above
    train_dataset=train_dataset,         # training dataset
    eval_dataset=valid_dataset,          # evaluation dataset
    compute_metrics=compute_metrics,     # the callback that computes metrics of interest
)

Đào tạo người mẫu:

# train the model
trainer.train()

Quá trình đào tạo mất vài giờ để kết thúc, tùy thuộc vào GPU của bạn. Nếu bạn đang sử dụng phiên bản Colab miễn phí, sẽ mất một giờ với NVIDIA Tesla K80. Đây là kết quả:

***** Running training *****
  Num examples = 14628
  Num Epochs = 1
  Instantaneous batch size per device = 10
  Total train batch size (w. parallel, distributed & accumulation) = 10
  Gradient Accumulation steps = 1
  Total optimization steps = 1463
 [1463/1463 41:07, Epoch 1/1]
Step	Training Loss	Validation Loss	Accuracy
200		0.250800		0.100533		0.983867
400		0.027600		0.043009		0.993437
600		0.023400		0.017812		0.997539
800		0.014900		0.030269		0.994258
1000	0.022400		0.012961		0.998086
1200	0.009800		0.010561		0.998633
1400	0.007700		0.010300		0.998633
***** Running Evaluation *****
  Num examples = 3657
  Batch size = 20
Saving model checkpoint to ./results/checkpoint-200
Configuration saved in ./results/checkpoint-200/config.json
Model weights saved in ./results/checkpoint-200/pytorch_model.bin
<SNIPPED>
***** Running Evaluation *****
  Num examples = 3657
  Batch size = 20
Saving model checkpoint to ./results/checkpoint-1400
Configuration saved in ./results/checkpoint-1400/config.json
Model weights saved in ./results/checkpoint-1400/pytorch_model.bin

Training completed. Do not forget to share your model on huggingface.co/models =)

Loading best model from ./results/checkpoint-1400 (score: 0.010299865156412125).
TrainOutput(global_step=1463, training_loss=0.04888018785440506, metrics={'train_runtime': 2469.1722, 'train_samples_per_second': 5.924, 'train_steps_per_second': 0.593, 'total_flos': 3848788517806080.0, 'train_loss': 0.04888018785440506, 'epoch': 1.0})

Đánh giá mô hình

load_best_model_at_endđược đặt thành True, mức tạ tốt nhất sẽ được tải khi quá trình tập luyện hoàn thành. Hãy đánh giá nó với bộ xác thực của chúng tôi:

# evaluate the current model after training
trainer.evaluate()

Đầu ra:

***** Running Evaluation *****
  Num examples = 3657
  Batch size = 20
 [183/183 02:11]
{'epoch': 1.0,
 'eval_accuracy': 0.998632759092152,
 'eval_loss': 0.010299865156412125,
 'eval_runtime': 132.0374,
 'eval_samples_per_second': 27.697,
 'eval_steps_per_second': 1.386}

Lưu mô hình và tokenizer:

# saving the fine tuned model & tokenizer
model_path = "fake-news-bert-base-uncased"
model.save_pretrained(model_path)
tokenizer.save_pretrained(model_path)

Một thư mục mới chứa cấu hình mô hình và trọng số sẽ xuất hiện sau khi chạy ô trên. Nếu bạn muốn thực hiện dự đoán, bạn chỉ cần sử dụng from_pretrained()phương pháp chúng tôi đã sử dụng khi tải mô hình và bạn đã sẵn sàng.

Tiếp theo, hãy tạo một hàm chấp nhận văn bản bài viết làm đối số và trả về cho dù nó là giả mạo hay không:

def get_prediction(text, convert_to_label=False):
    # prepare our text into tokenized sequence
    inputs = tokenizer(text, padding=True, truncation=True, max_length=max_length, return_tensors="pt").to("cuda")
    # perform inference to our model
    outputs = model(**inputs)
    # get output probabilities by doing softmax
    probs = outputs[0].softmax(1)
    # executing argmax function to get the candidate label
    d = {
        0: "reliable",
        1: "fake"
    }
    if convert_to_label:
      return d[int(probs.argmax())]
    else:
      return int(probs.argmax())

Tôi đã lấy một ví dụ từ test.csvmô hình chưa từng thấy để thực hiện suy luận, tôi đã kiểm tra nó và đó là một bài báo thực tế từ The New York Times:

real_news = """
Tim Tebow Will Attempt Another Comeback, This Time in Baseball - The New York Times",Daniel Victor,"If at first you don’t succeed, try a different sport. Tim Tebow, who was a Heisman   quarterback at the University of Florida but was unable to hold an N. F. L. job, is pursuing a career in Major League Baseball. <SNIPPED>
"""

Văn bản gốc nằm trong môi trường Colab nếu bạn muốn sao chép nó, vì nó là một bài báo hoàn chỉnh. Hãy chuyển nó cho mô hình và xem kết quả:

get_prediction(real_news, convert_to_label=True)

Đầu ra:

reliable

Phụ lục: Tạo tệp đệ trình cho Kaggle

Trong phần này, chúng tôi sẽ dự đoán tất cả các bài trong phần test.csvđể tạo hồ sơ gửi để xem độ chính xác của chúng tôi trong bộ bài kiểm tra của cuộc thi Kaggle :

# read the test set
test_df = pd.read_csv("test.csv")
# make a copy of the testing set
new_df = test_df.copy()
# add a new column that contains the author, title and article content
new_df["new_text"] = new_df["author"].astype(str) + " : " + new_df["title"].astype(str) + " - " + new_df["text"].astype(str)
# get the prediction of all the test set
new_df["label"] = new_df["new_text"].apply(get_prediction)
# make the submission file
final_df = new_df[["id", "label"]]
final_df.to_csv("submit_final.csv", index=False)

Sau khi chúng tôi nối tác giả, tiêu đề và văn bản bài viết với nhau, chúng tôi truyền get_prediction()hàm vào cột mới để lấp đầy labelcột, sau đó chúng tôi sử dụng to_csv()phương thức để tạo tệp gửi cho Kaggle. Đây là điểm nộp bài của tôi:

Điểm nộp hồ sơ

Chúng tôi nhận được độ chính xác 99,78% và 100% trên bảng xếp hạng riêng tư và công khai. Thật tuyệt vời!

Kết Luận

Được rồi, chúng ta đã hoàn thành phần hướng dẫn. Bạn có thể kiểm tra trang này để xem các thông số đào tạo khác nhau mà bạn có thể điều chỉnh.

Nếu bạn có tập dữ liệu tin tức giả tùy chỉnh để tinh chỉnh, bạn chỉ cần chuyển danh sách các mẫu cho trình mã hóa như chúng tôi đã làm, bạn sẽ không thay đổi bất kỳ mã nào khác sau đó.

Kiểm tra mã hoàn chỉnh tại đây hoặc môi trường Colab tại đây .

Como construir um detector de notícias falsas em Python

Explorando o conjunto de dados de notícias falsas, realizando análises de dados, como nuvens de palavras e ngrams, e ajustando o transformador BERT para construir um detector de notícias falsas em Python usando a biblioteca de transformadores.

Fake news é a transmissão intencional de alegações falsas ou enganosas como notícias, onde as declarações são propositalmente enganosas.

Jornais, tablóides e revistas foram suplantados por plataformas de notícias digitais, blogs, feeds de mídia social e uma infinidade de aplicativos de notícias móveis. As organizações de notícias se beneficiaram do aumento do uso de mídias sociais e plataformas móveis, fornecendo aos assinantes informações atualizadas.

Os consumidores agora têm acesso instantâneo às últimas notícias. Essas plataformas de mídia digital ganharam destaque devido à sua fácil conexão com o resto do mundo e permitem aos usuários discutir e compartilhar ideias e debater temas como democracia, educação, saúde, pesquisa e história. As notícias falsas nas plataformas digitais estão cada vez mais populares e são usadas para fins lucrativos, como ganhos políticos e financeiros.

Quão Grande é este Problema?

Como a Internet, as mídias sociais e as plataformas digitais são amplamente utilizadas, qualquer pessoa pode propagar informações imprecisas e tendenciosas. É quase impossível evitar a disseminação de notícias falsas. Há um tremendo aumento na distribuição de notícias falsas, que não se restringe a um setor como a política, mas inclui esportes, saúde, história, entretenimento, ciência e pesquisa.

A solução

É vital reconhecer e diferenciar entre notícias falsas e verdadeiras. Um método é fazer com que um especialista decida e verifique cada informação, mas isso leva tempo e requer conhecimentos que não podem ser compartilhados. Em segundo lugar, podemos usar ferramentas de aprendizado de máquina e inteligência artificial para automatizar a identificação de notícias falsas.

As informações de notícias on-line incluem vários dados de formato não estruturado (como documentos, vídeos e áudio), mas vamos nos concentrar nas notícias em formato de texto aqui. Com o progresso do aprendizado de máquina e do processamento de linguagem natural , agora podemos reconhecer o caráter enganoso e falso de um artigo ou declaração.

Vários estudos e experimentos estão sendo realizados para detectar notícias falsas em todos os meios.

Nosso principal objetivo deste tutorial é:

  • Explore e analise o conjunto de dados de Fake News.
  • Construa um classificador que possa distinguir Fake news com o máximo de precisão possível.

Aqui está a tabela de conteúdo:

  • Introdução
  • Quão Grande é este Problema?
  • A solução
  • Exploração de dados
    • Distribuição de aulas
  • Limpeza de dados para análise
  • Análise Explorativa de Dados
    • Nuvem de palavra única
    • Bigrama mais frequente (combinação de duas palavras)
    • Trigrama mais frequente (combinação de três palavras)
  • Construindo um classificador ajustando o BERT
    • Preparação de dados
    • Tokenização do conjunto de dados
    • Carregando e Ajustando o Modelo
    • Avaliação do modelo
  • Apêndice: Criando um arquivo de envio para o Kaggle
  • Conclusão

Exploração de dados

Neste trabalho, utilizamos o conjunto de dados de notícias falsas do Kaggle para classificar notícias não confiáveis ​​como notícias falsas. Temos um conjunto de dados de treinamento completo contendo as seguintes características:

  • id: ID exclusivo para um artigo de notícias
  • title: título de uma notícia
  • author: autor da reportagem
  • text: texto do artigo; pode estar incompleto
  • label: um rótulo que marca o artigo como potencialmente não confiável indicado por 1 (não confiável ou falso) ou 0 (confiável).

É um problema de classificação binária no qual devemos prever se uma determinada notícia é confiável ou não.

Se você tiver uma conta Kaggle, basta baixar o conjunto de dados do site e extrair o arquivo ZIP.

Também carreguei o conjunto de dados no Google Drive, e você pode obtê-lo aqui ou usar a gdownbiblioteca para baixá-lo automaticamente nos notebooks do Google Colab ou Jupyter:

$ pip install gdown
# download from Google Drive
$ gdown "https://drive.google.com/uc?id=178f_VkNxccNidap-5-uffXUW475pAuPy&confirm=t"
Downloading...
From: https://drive.google.com/uc?id=178f_VkNxccNidap-5-uffXUW475pAuPy&confirm=t
To: /content/fake-news.zip
100% 48.7M/48.7M [00:00<00:00, 74.6MB/s]

Descompactando os arquivos:

$ unzip fake-news.zip

Três arquivos aparecerão no diretório de trabalho atual: train.csv, test.csv, e submit.csv, que usaremos train.csvna maior parte do tutorial.

Instalando as dependências necessárias:

$ pip install transformers nltk pandas numpy matplotlib seaborn wordcloud

Nota: Se você estiver em um ambiente local, certifique-se de instalar o PyTorch para GPU, vá para esta página para uma instalação adequada.

Vamos importar as bibliotecas essenciais para análise:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

Os corpora e módulos NLTK devem ser instalados usando o downloader NLTK padrão:

import nltk
nltk.download('stopwords')
nltk.download('wordnet')

O conjunto de dados de notícias falsas inclui títulos e textos de artigos originais e fictícios de vários autores. Vamos importar nosso conjunto de dados:

# load the dataset
news_d = pd.read_csv("train.csv")
print("Shape of News data:", news_d.shape)
print("News data columns", news_d.columns)

Saída:

 Shape of News data: (20800, 5)
 News data columns Index(['id', 'title', 'author', 'text', 'label'], dtype='object')

Veja como fica o conjunto de dados:

# by using df.head(), we can immediately familiarize ourselves with the dataset. 
news_d.head()

Saída:

id	title	author	text	label
0	0	House Dem Aide: We Didn’t Even See Comey’s Let...	Darrell Lucus	House Dem Aide: We Didn’t Even See Comey’s Let...	1
1	1	FLYNN: Hillary Clinton, Big Woman on Campus - ...	Daniel J. Flynn	Ever get the feeling your life circles the rou...	0
2	2	Why the Truth Might Get You Fired	Consortiumnews.com	Why the Truth Might Get You Fired October 29, ...	1
3	3	15 Civilians Killed In Single US Airstrike Hav...	Jessica Purkiss	Videos 15 Civilians Killed In Single US Airstr...	1
4	4	Iranian woman jailed for fictional unpublished...	Howard Portnoy	Print \nAn Iranian woman has been sentenced to...	1

Temos 20.800 linhas, que têm cinco colunas. Vamos ver algumas estatísticas da textcoluna:

#Text Word startistics: min.mean, max and interquartile range

txt_length = news_d.text.str.split().str.len()
txt_length.describe()

Saída:

count    20761.000000
mean       760.308126
std        869.525988
min          0.000000
25%        269.000000
50%        556.000000
75%       1052.000000
max      24234.000000
Name: text, dtype: float64

Estatísticas da titlecoluna:

#Title statistics 

title_length = news_d.title.str.split().str.len()
title_length.describe()

Saída:

count    20242.000000
mean        12.420709
std          4.098735
min          1.000000
25%         10.000000
50%         13.000000
75%         15.000000
max         72.000000
Name: title, dtype: float64

As estatísticas para os conjuntos de treinamento e teste são as seguintes:

  • O textatributo possui maior contagem de palavras com média de 760 palavras e 75% com mais de 1000 palavras.
  • O titleatributo é uma declaração curta com uma média de 12 palavras, sendo que 75% delas são em torno de 15 palavras.

Nosso experimento seria com texto e título juntos.

Distribuição de aulas

Contando parcelas para ambos os rótulos:

sns.countplot(x="label", data=news_d);
print("1: Unreliable")
print("0: Reliable")
print("Distribution of labels:")
print(news_d.label.value_counts());

Saída:

1: Unreliable
0: Reliable
Distribution of labels:
1    10413
0    10387
Name: label, dtype: int64

Distribuição de rótulos

print(round(news_d.label.value_counts(normalize=True),2)*100);

Saída:

1    50.0
0    50.0
Name: label, dtype: float64

O número de artigos não confiáveis ​​(falsos ou 1) é 10.413, enquanto o número de artigos confiáveis ​​(confiáveis ​​ou 0) é 10.387. Quase 50% dos artigos são falsos. Portanto, a métrica de precisão medirá o desempenho do nosso modelo ao construir um classificador.

Limpeza de dados para análise

Nesta seção, vamos limpar nosso conjunto de dados para fazer algumas análises:

  • Elimine linhas e colunas não utilizadas.
  • Execute a imputação de valor nulo.
  • Remova os caracteres especiais.
  • Remova palavras de parada.
# Constants that are used to sanitize the datasets 

column_n = ['id', 'title', 'author', 'text', 'label']
remove_c = ['id','author']
categorical_features = []
target_col = ['label']
text_f = ['title', 'text']
# Clean Datasets
import nltk
from nltk.corpus import stopwords
import re
from nltk.stem.porter import PorterStemmer
from collections import Counter

ps = PorterStemmer()
wnl = nltk.stem.WordNetLemmatizer()

stop_words = stopwords.words('english')
stopwords_dict = Counter(stop_words)

# Removed unused clumns
def remove_unused_c(df,column_n=remove_c):
    df = df.drop(column_n,axis=1)
    return df

# Impute null values with None
def null_process(feature_df):
    for col in text_f:
        feature_df.loc[feature_df[col].isnull(), col] = "None"
    return feature_df

def clean_dataset(df):
    # remove unused column
    df = remove_unused_c(df)
    #impute null values
    df = null_process(df)
    return df

# Cleaning text from unused characters
def clean_text(text):
    text = str(text).replace(r'http[\w:/\.]+', ' ')  # removing urls
    text = str(text).replace(r'[^\.\w\s]', ' ')  # remove everything but characters and punctuation
    text = str(text).replace('[^a-zA-Z]', ' ')
    text = str(text).replace(r'\s\s+', ' ')
    text = text.lower().strip()
    #text = ' '.join(text)    
    return text

## Nltk Preprocessing include:
# Stop words, Stemming and Lemmetization
# For our project we use only Stop word removal
def nltk_preprocess(text):
    text = clean_text(text)
    wordlist = re.sub(r'[^\w\s]', '', text).split()
    #text = ' '.join([word for word in wordlist if word not in stopwords_dict])
    #text = [ps.stem(word) for word in wordlist if not word in stopwords_dict]
    text = ' '.join([wnl.lemmatize(word) for word in wordlist if word not in stopwords_dict])
    return  text

No bloco de código acima:

  • Importamos o NLTK, que é uma famosa plataforma de desenvolvimento de aplicativos Python que interagem com a linguagem humana. Em seguida, importamos repara regex.
  • Importamos palavras irrelevantes de nltk.corpus. Ao trabalhar com palavras, principalmente ao considerar a semântica, às vezes precisamos eliminar palavras comuns que não adicionam nenhum significado significativo a uma declaração, como "but", "can", "we", etc.
  • PorterStemmeré usado para executar palavras derivadas com NLTK. Stemmers retiram palavras de seus afixos morfológicos, deixando apenas o radical da palavra.
  • Importamos WordNetLemmatizer()da biblioteca NLTK para lematização. A lematização é muito mais eficaz do que a derivação . Ele vai além da redução de palavras e avalia todo o léxico de uma língua para aplicar a análise morfológica às palavras, com o objetivo de apenas remover as extremidades flexionais e retornar a forma base ou dicionário de uma palavra, conhecida como lema.
  • stopwords.words('english')permite-nos ver a lista de todas as palavras de parada em inglês suportadas pelo NLTK.
  • remove_unused_c()A função é usada para remover as colunas não utilizadas.
  • Nós imputamos valores nulos Noneusando a null_process()função.
  • Dentro da função clean_dataset(), chamamos remove_unused_c()e null_process()funções. Esta função é responsável pela limpeza dos dados.
  • Para limpar o texto de caracteres não utilizados, criamos a clean_text()função.
  • Para pré-processamento, usaremos apenas a remoção de palavras de parada. Criamos a nltk_preprocess()função para isso.

Pré-processando o texte title:

# Perform data cleaning on train and test dataset by calling clean_dataset function
df = clean_dataset(news_d)
# apply preprocessing on text through apply method by calling the function nltk_preprocess
df["text"] = df.text.apply(nltk_preprocess)
# apply preprocessing on title through apply method by calling the function nltk_preprocess
df["title"] = df.title.apply(nltk_preprocess)
# Dataset after cleaning and preprocessing step
df.head()

Saída:

title	text	label
0	house dem aide didnt even see comeys letter ja...	house dem aide didnt even see comeys letter ja...	1
1	flynn hillary clinton big woman campus breitbart	ever get feeling life circle roundabout rather...	0
2	truth might get fired	truth might get fired october 29 2016 tension ...	1
3	15 civilian killed single u airstrike identified	video 15 civilian killed single u airstrike id...	1
4	iranian woman jailed fictional unpublished sto...	print iranian woman sentenced six year prison ...	1

Análise Explorativa de Dados

Nesta seção, vamos realizar:

  • Análise Univariada : É uma análise estatística do texto. Usaremos a nuvem de palavras para esse propósito. Uma nuvem de palavras é uma abordagem de visualização de dados de texto em que o termo mais comum é apresentado no tamanho de fonte mais considerável.
  • Análise Bivariada : Bigrama e Trigrama serão usados ​​aqui. Segundo a Wikipedia: " um n-grama é uma sequência contígua de n itens de uma determinada amostra de texto ou fala. De acordo com a aplicação, os itens podem ser fonemas, sílabas, letras, palavras ou pares de bases. Os n-gramas são normalmente coletados de um texto ou corpus de fala".

Nuvem de palavra única

As palavras mais frequentes aparecem em negrito e fonte maior em uma nuvem de palavras. Esta seção realizará uma nuvem de palavras para todas as palavras no conjunto de dados.

A função da biblioteca WordCloudwordcloud() será usada, e o generate()é utilizado para gerar a imagem da nuvem de palavras:

from wordcloud import WordCloud, STOPWORDS
import matplotlib.pyplot as plt

# initialize the word cloud
wordcloud = WordCloud( background_color='black', width=800, height=600)
# generate the word cloud by passing the corpus
text_cloud = wordcloud.generate(' '.join(df['text']))
# plotting the word cloud
plt.figure(figsize=(20,30))
plt.imshow(text_cloud)
plt.axis('off')
plt.show()

Saída:

WordCloud para todos os dados de notícias falsas

Nuvem de palavras apenas para notícias confiáveis:

true_n = ' '.join(df[df['label']==0]['text']) 
wc = wordcloud.generate(true_n)
plt.figure(figsize=(20,30))
plt.imshow(wc)
plt.axis('off')
plt.show()

Saída:

Word Cloud para notícias confiáveis

Nuvem de palavras apenas para notícias falsas:

fake_n = ' '.join(df[df['label']==1]['text'])
wc= wordcloud.generate(fake_n)
plt.figure(figsize=(20,30))
plt.imshow(wc)
plt.axis('off')
plt.show()

Saída:

Nuvem de palavras para notícias falsas

Bigrama mais frequente (combinação de duas palavras)

Um N-gram é uma sequência de letras ou palavras. Um unigrama de caractere é composto por um único caractere, enquanto um bigrama compreende uma série de dois caracteres. Da mesma forma, os N-gramas de palavras são compostos de uma série de n palavras. A palavra "unidos" é um 1 grama (unigrama). A combinação das palavras "estado unido" é um 2 gramas (bigrama), "nova york cidade" é um 3 gramas.

Vamos traçar o bigrama mais comum nas notícias confiáveis:

def plot_top_ngrams(corpus, title, ylabel, xlabel="Number of Occurences", n=2):
  """Utility function to plot top n-grams"""
  true_b = (pd.Series(nltk.ngrams(corpus.split(), n)).value_counts())[:20]
  true_b.sort_values().plot.barh(color='blue', width=.9, figsize=(12, 8))
  plt.title(title)
  plt.ylabel(ylabel)
  plt.xlabel(xlabel)
  plt.show()
plot_top_ngrams(true_n, 'Top 20 Frequently Occuring True news Bigrams', "Bigram", n=2)

Principais bigramas em notícias falsas

O bigrama mais comum nas notícias falsas:

plot_top_ngrams(fake_n, 'Top 20 Frequently Occuring Fake news Bigrams', "Bigram", n=2)

Principais bigramas em notícias falsas

Trigrama mais frequente (combinação de três palavras)

O trigrama mais comum em notícias confiáveis:

plot_top_ngrams(true_n, 'Top 20 Frequently Occuring True news Trigrams', "Trigrams", n=3)

O trigrama mais comum em notícias falsas

Para notícias falsas agora:

plot_top_ngrams(fake_n, 'Top 20 Frequently Occuring Fake news Trigrams', "Trigrams", n=3)

Trigramas mais comuns em Fake news

Os gráficos acima nos dão algumas ideias de como as duas classes se parecem. Na próxima seção, usaremos a biblioteca de transformadores para construir um detector de notícias falsas.

Construindo um classificador ajustando o BERT

Esta seção irá pegar o código extensivamente do tutorial BERT de ajuste fino para fazer um classificador de notícias falsas usando a biblioteca de transformadores. Portanto, para obter informações mais detalhadas, você pode acessar o tutorial original .

Se você não instalou transformadores, você deve:

$ pip install transformers

Vamos importar as bibliotecas necessárias:

import torch
from transformers.file_utils import is_tf_available, is_torch_available, is_torch_tpu_available
from transformers import BertTokenizerFast, BertForSequenceClassification
from transformers import Trainer, TrainingArguments
import numpy as np
from sklearn.model_selection import train_test_split

import random

Queremos tornar nossos resultados reproduzíveis mesmo se reiniciarmos nosso ambiente:

def set_seed(seed: int):
    """
    Helper function for reproducible behavior to set the seed in ``random``, ``numpy``, ``torch`` and/or ``tf`` (if
    installed).

    Args:
        seed (:obj:`int`): The seed to set.
    """
    random.seed(seed)
    np.random.seed(seed)
    if is_torch_available():
        torch.manual_seed(seed)
        torch.cuda.manual_seed_all(seed)
        # ^^ safe to call this function even if cuda is not available
    if is_tf_available():
        import tensorflow as tf

        tf.random.set_seed(seed)

set_seed(1)

O modelo que vamos usar é o bert-base-uncased:

# the model we gonna train, base uncased BERT
# check text classification models here: https://huggingface.co/models?filter=text-classification
model_name = "bert-base-uncased"
# max sequence length for each document/sentence sample
max_length = 512

Carregando o tokenizador:

# load the tokenizer
tokenizer = BertTokenizerFast.from_pretrained(model_name, do_lower_case=True)

Preparação de dados

Vamos agora limpar os NaNvalores das colunas text, authore :title

news_df = news_d[news_d['text'].notna()]
news_df = news_df[news_df["author"].notna()]
news_df = news_df[news_df["title"].notna()]

Em seguida, criando uma função que recebe o conjunto de dados como um dataframe do Pandas e retorna as divisões de trem/validação de textos e rótulos como listas:

def prepare_data(df, test_size=0.2, include_title=True, include_author=True):
  texts = []
  labels = []
  for i in range(len(df)):
    text = df["text"].iloc[i]
    label = df["label"].iloc[i]
    if include_title:
      text = df["title"].iloc[i] + " - " + text
    if include_author:
      text = df["author"].iloc[i] + " : " + text
    if text and label in [0, 1]:
      texts.append(text)
      labels.append(label)
  return train_test_split(texts, labels, test_size=test_size)

train_texts, valid_texts, train_labels, valid_labels = prepare_data(news_df)

A função acima pega o conjunto de dados em um tipo de dataframe e os retorna como listas divididas em conjuntos de treinamento e validação. Definir include_titlepara Truesignifica que adicionamos a titlecoluna ao textque vamos usar para treinamento, definir include_authorpara Truesignifica que também adicionamos o authorao texto.

Vamos garantir que os rótulos e os textos tenham o mesmo comprimento:

print(len(train_texts), len(train_labels))
print(len(valid_texts), len(valid_labels))

Saída:

14628 14628
3657 3657

Tokenização do conjunto de dados

Vamos usar o tokenizer BERT para tokenizar nosso conjunto de dados:

# tokenize the dataset, truncate when passed `max_length`, 
# and pad with 0's when less than `max_length`
train_encodings = tokenizer(train_texts, truncation=True, padding=True, max_length=max_length)
valid_encodings = tokenizer(valid_texts, truncation=True, padding=True, max_length=max_length)

Convertendo as codificações em um conjunto de dados PyTorch:

class NewsGroupsDataset(torch.utils.data.Dataset):
    def __init__(self, encodings, labels):
        self.encodings = encodings
        self.labels = labels

    def __getitem__(self, idx):
        item = {k: torch.tensor(v[idx]) for k, v in self.encodings.items()}
        item["labels"] = torch.tensor([self.labels[idx]])
        return item

    def __len__(self):
        return len(self.labels)

# convert our tokenized data into a torch Dataset
train_dataset = NewsGroupsDataset(train_encodings, train_labels)
valid_dataset = NewsGroupsDataset(valid_encodings, valid_labels)

Carregando e Ajustando o Modelo

Usaremos BertForSequenceClassificationpara carregar nosso modelo de transformador BERT:

# load the model
model = BertForSequenceClassification.from_pretrained(model_name, num_labels=2)

Definimos num_labelscomo 2, pois é uma classificação binária. A função abaixo é um retorno de chamada para calcular a precisão em cada etapa de validação:

from sklearn.metrics import accuracy_score

def compute_metrics(pred):
  labels = pred.label_ids
  preds = pred.predictions.argmax(-1)
  # calculate accuracy using sklearn's function
  acc = accuracy_score(labels, preds)
  return {
      'accuracy': acc,
  }

Vamos inicializar os parâmetros de treinamento:

training_args = TrainingArguments(
    output_dir='./results',          # output directory
    num_train_epochs=1,              # total number of training epochs
    per_device_train_batch_size=10,  # batch size per device during training
    per_device_eval_batch_size=20,   # batch size for evaluation
    warmup_steps=100,                # number of warmup steps for learning rate scheduler
    logging_dir='./logs',            # directory for storing logs
    load_best_model_at_end=True,     # load the best model when finished training (default metric is loss)
    # but you can specify `metric_for_best_model` argument to change to accuracy or other metric
    logging_steps=200,               # log & save weights each logging_steps
    save_steps=200,
    evaluation_strategy="steps",     # evaluate each `logging_steps`
)

Eu configurei o per_device_train_batch_sizepara 10, mas você deve defini-lo o mais alto que sua GPU possa caber. Definindo o logging_stepse save_stepspara 200, o que significa que vamos realizar a avaliação e salvar os pesos do modelo em cada 200 etapas de treinamento.

Você pode verificar  esta página  para obter informações mais detalhadas sobre os parâmetros de treinamento disponíveis.

Vamos instanciar o treinador:

trainer = Trainer(
    model=model,                         # the instantiated Transformers model to be trained
    args=training_args,                  # training arguments, defined above
    train_dataset=train_dataset,         # training dataset
    eval_dataset=valid_dataset,          # evaluation dataset
    compute_metrics=compute_metrics,     # the callback that computes metrics of interest
)

Treinando o modelo:

# train the model
trainer.train()

O treinamento leva algumas horas para terminar, dependendo da sua GPU. Se você estiver na versão gratuita do Colab, deve levar uma hora com o NVIDIA Tesla K80. Aqui está a saída:

***** Running training *****
  Num examples = 14628
  Num Epochs = 1
  Instantaneous batch size per device = 10
  Total train batch size (w. parallel, distributed & accumulation) = 10
  Gradient Accumulation steps = 1
  Total optimization steps = 1463
 [1463/1463 41:07, Epoch 1/1]
Step	Training Loss	Validation Loss	Accuracy
200		0.250800		0.100533		0.983867
400		0.027600		0.043009		0.993437
600		0.023400		0.017812		0.997539
800		0.014900		0.030269		0.994258
1000	0.022400		0.012961		0.998086
1200	0.009800		0.010561		0.998633
1400	0.007700		0.010300		0.998633
***** Running Evaluation *****
  Num examples = 3657
  Batch size = 20
Saving model checkpoint to ./results/checkpoint-200
Configuration saved in ./results/checkpoint-200/config.json
Model weights saved in ./results/checkpoint-200/pytorch_model.bin
<SNIPPED>
***** Running Evaluation *****
  Num examples = 3657
  Batch size = 20
Saving model checkpoint to ./results/checkpoint-1400
Configuration saved in ./results/checkpoint-1400/config.json
Model weights saved in ./results/checkpoint-1400/pytorch_model.bin

Training completed. Do not forget to share your model on huggingface.co/models =)

Loading best model from ./results/checkpoint-1400 (score: 0.010299865156412125).
TrainOutput(global_step=1463, training_loss=0.04888018785440506, metrics={'train_runtime': 2469.1722, 'train_samples_per_second': 5.924, 'train_steps_per_second': 0.593, 'total_flos': 3848788517806080.0, 'train_loss': 0.04888018785440506, 'epoch': 1.0})

Avaliação do modelo

Como load_best_model_at_endestá definido como True, os melhores pesos serão carregados quando o treinamento for concluído. Vamos avaliá-lo com nosso conjunto de validação:

# evaluate the current model after training
trainer.evaluate()

Saída:

***** Running Evaluation *****
  Num examples = 3657
  Batch size = 20
 [183/183 02:11]
{'epoch': 1.0,
 'eval_accuracy': 0.998632759092152,
 'eval_loss': 0.010299865156412125,
 'eval_runtime': 132.0374,
 'eval_samples_per_second': 27.697,
 'eval_steps_per_second': 1.386}

Salvando o modelo e o tokenizer:

# saving the fine tuned model & tokenizer
model_path = "fake-news-bert-base-uncased"
model.save_pretrained(model_path)
tokenizer.save_pretrained(model_path)

Uma nova pasta contendo a configuração do modelo e pesos aparecerá após a execução da célula acima. Se você deseja realizar a previsão, basta usar o from_pretrained()método que usamos quando carregamos o modelo e pronto.

Em seguida, vamos fazer uma função que aceite o texto do artigo como argumento e retorne se é falso ou não:

def get_prediction(text, convert_to_label=False):
    # prepare our text into tokenized sequence
    inputs = tokenizer(text, padding=True, truncation=True, max_length=max_length, return_tensors="pt").to("cuda")
    # perform inference to our model
    outputs = model(**inputs)
    # get output probabilities by doing softmax
    probs = outputs[0].softmax(1)
    # executing argmax function to get the candidate label
    d = {
        0: "reliable",
        1: "fake"
    }
    if convert_to_label:
      return d[int(probs.argmax())]
    else:
      return int(probs.argmax())

Peguei um exemplo de test.csvque o modelo nunca viu fazer inferência, eu verifiquei, e é um artigo real do The New York Times:

real_news = """
Tim Tebow Will Attempt Another Comeback, This Time in Baseball - The New York Times",Daniel Victor,"If at first you don’t succeed, try a different sport. Tim Tebow, who was a Heisman   quarterback at the University of Florida but was unable to hold an N. F. L. job, is pursuing a career in Major League Baseball. <SNIPPED>
"""

O texto original está no ambiente Colab caso queira copiá-lo, pois é um artigo completo. Vamos passar para o modelo e ver os resultados:

get_prediction(real_news, convert_to_label=True)

Saída:

reliable

Apêndice: Criando um arquivo de envio para o Kaggle

Nesta seção, vamos prever todos os artigos test.csvpara criar um arquivo de submissão para ver nossa precisão no teste definido na competição Kaggle :

# read the test set
test_df = pd.read_csv("test.csv")
# make a copy of the testing set
new_df = test_df.copy()
# add a new column that contains the author, title and article content
new_df["new_text"] = new_df["author"].astype(str) + " : " + new_df["title"].astype(str) + " - " + new_df["text"].astype(str)
# get the prediction of all the test set
new_df["label"] = new_df["new_text"].apply(get_prediction)
# make the submission file
final_df = new_df[["id", "label"]]
final_df.to_csv("submit_final.csv", index=False)

Depois de concatenar o autor, título e texto do artigo juntos, passamos a get_prediction()função para a nova coluna para preencher a labelcoluna, então usamos to_csv()o método para criar o arquivo de submissão para o Kaggle. Aqui está a minha pontuação de submissão:

Pontuação de envio

Obtivemos 99,78% e 100% de precisão nas tabelas de classificação privadas e públicas. Fantástico!

Conclusão

Pronto, terminamos o tutorial. Você pode verificar esta página para ver vários parâmetros de treinamento que você pode ajustar.

Se você tiver um conjunto de dados de notícias falsas personalizado para ajuste fino, basta passar uma lista de amostras para o tokenizer como fizemos, você não alterará nenhum outro código depois disso.

Confira o código completo aqui , ou o ambiente Colab aqui .