Identifying Toxicity in Arabic Text Using the Perspective API

Disclaimer: This article explores the Perspective API for online toxic comments predictions. Some toxic comments shown in this article are samples selected for illustration purposes and do not represent the views of the author.

The increasing number of online platforms for user-generated content enable more people to experience the freedom of expression than ever before. In addition, users of these platforms can be anonymous and hide their identity, which can increase the chance of misusing these platforms. Online abusive and toxic conversation creates an exclusive environment and in more severe cases, it can foster real-world violence. Freedom of expression or speech should not promote harmful content like hate speech, bullying, or abusive behavior, and it needs protections to certify a safe and engaging environment in which all participants can freely express themselves without fear. 

Some countries have issued laws to ban hate speech, a kind of offensive language, on social networking platforms. For example, in 2017, Germany passed the Network Enforcement Act, a law that requires social media companies to remove hate speech from their websites. In addition to legislative reforms, technological solutions have been adopted to enforcing these reforms. 

In this Article, we will explore the Perspective API to identify toxic tweets written in the Arabic and English languages. The main content of this article is summarized in the following points: 

  1. Definition of toxicity in online comments.
  2. Introduction to the Perspective API and its main features.
  3. Dataset selection.
  4. Applying the Perspective API.
  5. Evaluating samples from the results.

Definition of toxicity in online comments:

Risch and Krestel (2020) define a toxic comment as a rude, disrespectful, or unreasonable comment that is likely to make other users leave a discussion. The OpenWeb divides toxic comments based on two main categories: hate speech and online harassment or trolling.

An example of a toxic comment

Introduction to the Perspective API and its main features:

Google and the research group Jigsaw develop the Perspective API to promote better online conversations. The Perspective API applies machine learning algorithms to identify toxic comments and provide scores for 6 main attributes:

  • Severe Toxicity
  • Insult
  • Profanity
  • Identity attack
  • Threat
  • Sexually explicit

The perspective API is hosted on Google Cloud Platform. It is publicly available for free and support multiple languages; such as Arabic, Chinese, Czech, Dutch, English, French, German, Hindi, Hinglish, Indonesian, Italian, Japanese, Korean, Polish, Portuguese, Russian, and Spanish. 

Source: https://developers.perspectiveapi.com/s/about-the-api

To get started with your project, you need to follow the instruction on this Doc and request an API access.

Dataset selection:

We select a recent topic that creates a controversial online Twitter conversation and an outrage in the Islamic world, after a derogatory comments insulting Prophet Muhammad (PBUH) by two members of Prime Minister Narendra Modi’s Bharatiya Janata Party (BJP). We extracted an Arabic dataset from Twitter based on the keywords: “#إلا_رسول_الله_يامودى” or “#طرد_السفير_الهندي”, and an English dataset based on the keywords: “#India”, “#modi”, or “#Stopinsulting_ProphetMuhammad”. The datasets are available on this GitHub repository.

Source: https://www.aljazeera.com/news/2022/6/6/qatar-other-muslim-nations-condemn-india-over-anti-islam-remarks

Applying the Perspective API:

We will start by importing the libraries that are required during this exercise:

				
					# importing libraries
import json 
import requests 
import csv
import pandas as pd
import numpy as np
import string 
import re
				
			

Next, we need to provide our code of the Perspective API key to access the API. This code is  passed to the AnalyzeComment method to provide an API request and analyze the tweets based on the the requested attributes as we will discuss below. 

				
					# assigning the access code to the API
api_key = '## Add your code here ##' 
url = ('https://commentanalyzer.googleapis.com/v1alpha1/comments:analyze' +    
    '?key=' + api_key)
				
			

The next step is uploading and reading the datasets. We have two datasets, Arabic and English tweets. 

				
					# reading the English dataset
data_en = pd.read_csv('/content/Modi_Rasul_EN_6_2022.csv', header= None, names = 
 ['tweet_id',
    'tweet_text', 
    'tweet_location',
    'tweet_geo',
    'user_screen',
    'user_desc',
    'tweet_source',
    'tweet_created',
    'tweet_contributors',
    'tweet_entities',
    'tweet_retweet_count',
    'tweet_username',
    'tweet_followers_count'])

data_en

				
			
Samples from the English dataset
				
					# reading the Arabic dataset
data_ar = pd.read_csv('/content/Modi_Rasul_ARAR_6_2022.csv', header = 0, names = 
 ['tweet_id',
    'tweet_text', 
    'tweet_location',
    'tweet_geo',
    'user_screen',
    'user_desc',
    'tweet_source',
    'tweet_created',
    'tweet_contributors',
    'tweet_entities',
    'tweet_retweet_count',
    'tweet_username',
    'tweet_followers_count'])
data_ar
				
			
Samples from the Arabic dataset

Removing duplicated tweets before sending the request to the API can save from the processing times and resources.  In this step, we remove mentioned usernames, the retweet keyword (RT), and the newline character (\ln) then we remove the duplicates as the following:  

				
					# this method clean tweets to remove usernames, RT, and newline
def removingDuplication(tweet):
  tweet = str(tweet)
  # remove usermentions
  tweet = re.sub('@[a-zA-Z0-9_.-:]*', '', tweet)
  # remove retweet
  tweet = re.sub('RT', '', tweet)
  # Remove new line character
  tweet = re.sub('\n', ' ', tweet)
  return tweet

# defining arrays for the filtered tweets
filteredTweets_en = []
filteredTweets_ar = []

# sending the English and Arabic tweets to filter unwanted characters and prepare them for removing duplicate
for tweet in data_en['tweet_text']:
  twt = removingDuplication(tweet)
  filteredTweets_en.append(twt)

for tweet in data_ar['tweet_text']:
  twt = removingDuplication(tweet)
  filteredTweets_ar.append(twt)
  
# Convert the cleaned tweets format to a Pandas dataframe
df_en = pd.DataFrame({'tweet':filteredTweets_en})
df_ar = pd.DataFrame({'tweet':filteredTweets_ar})

# Checking the size of the dataframe before removing duplicated tweets
print("Number of English tweets before removing duplicates:", df_en.shape)
print("Number of Arabic tweets before removing duplicates:", df_ar.shape)

# Removing duplicates
df_en = df_en.drop_duplicates()
df_ar = df_ar.drop_duplicates()

# Checking the size of the dataframe after removing duplicated tweets
print("Number of English tweets after removing duplicates:", df_en.shape)
print("Number of Arabic tweets after removing duplicates:", df_ar.shape)
				
			
Output - Number of tweets before and after removing duplicates

Both datasets contain multiple duplicated tweets. As it is showing from the output screenshot above, the English dataset has 10,009 original tweets and 3,429 unique tweets. The Arabic dataset has 10,000 original tweets and 2,530 unique tweets. We will consider only the unique tweets from both datasets for further processing.

The perspective API has multiple attributes. Currently, the main attribute is “TOXICITY” and the others are: “SEVERE_TOXICITY”, “IDENTITY_ATTACK”, “INSULT”, “PROFANITY, THREAT”, “SEXUALLY_EXPLICIT”, and “FLIRTATION”. However, not all attributes are available for all languages. For the Arabic language, only the main “TOXICITY” attribute is available. The values of all attributes are probabilities between 0 and 1. The higher the value, the more likely the text belongs to the attribute predicted. 

The AnalyzeComment method provides an API request to analyze the tweets based on the the requested attributes. In this case, we use the TOXICITY model as it is the only attribute that is supported by the Arabic language and English language on the same time. 

We define a dictionary that contains: tweet’s text, language, and an attributes for the requested attributes as the predicted toxicity probability score.

The quota limit is set to an average of 1 query per second (QPS) for all Perspective projects. Thus, we select the first 200 tweets and the last 200 tweets from both languages datasets to be used for testing the Perspective API so we can perform this experiment within a reasonable time frame using the regular Colab environment with a GPU accelerator. We also use the time Python library to pause for 60 seconds between the request calls to the API using the sleep() function.

				
					# selecting the first 200 tweets from both Arabic and English datasets
df_short_en_f = df_en.iloc[:200]
df_short_ar_f = df_ar.iloc[:200]

# selecting the last 200 tweets from both Arabic and English datasets
df_short_en_l = df_en.iloc[-200:]
df_short_ar_l = df_ar.iloc[-200:]

# sending the request to the Perspective API
# importing time library
import time
# Define a dictionary to store the predicted toxicity probabilities scores
comment_scores = {}
i = 0
# the name of the dataset/ dataframe should be replaced with "df_short_ar_l" to analyze the last 200 Arabic tweets
for c in df_short_ar_f['tweet']:
  i = i + 1
  data_dict = {
    'comment': {'text': c},
    'languages': ['ar'],
    'requestedAttributes': {'TOXICITY': {}}
  }
  response = requests.post(url=url, data=json.dumps(data_dict)) 
  response_dict = json.loads(response.content)
  print (response_dict) 
  comment_scores[c] = response_dict['attributeScores']['TOXICITY']['summaryScore']['value']
  if (i % 10) == 0:
    time.sleep(60) 

# tweets textual content is saved in the keys
keys = comment_scores.keys()

# the predicted toxicity probabilities scores are saved in values
values = comment_scores.values()

print(comment_scores)
				
			
Samples from the output from the Arabic tweets

The same script above is used for both Arabic tweets dataframes by replacing the name of the dataframe. First applied to the “df_short_ar_f” and then applied to the “df_short_ar_l“. The predictions scores are then saved into a dataframe and a CSV file to support further analysis and testing. We also save the file to Google drive as the following: 

				
					# saving the predictions to a dataframe and then to a CSV file for further analysis
# replace the outputfile name with "Perspective_ar_last.csv" to save the predictions for the last 200 Arabic tweets

outputfile = "Perspective_ar_first.csv" 
df_Predictions_ar_f = pd.DataFrame({'tweet': keys, 'Predicted':values})

with open(outputfile, mode='w', newline='\n', encoding="utf-8-sig") as f:
            df_Predictions_ar_f.to_csv(f, sep=',', float_format='%.2f',
                              index=False, quoting=csv.QUOTE_MINIMAL)
                              

# saving the file to your Google drive
# replace the file name with "Perspective_ar_last.csv" to save the predictions for the last 200 Arabic tweets to the drive
# you will need to grant permission to Colab to access your Google drive
file_name = "Perspective_ar_first.csv" 

from googleapiclient.http import MediaFileUpload
from googleapiclient.discovery import build
from google.colab import auth

auth.authenticate_user()
drive_service = build('drive', 'v3')

def save_file_to_drive(name, path):
  file_metadata = {'name': name, 'mimeType': 'application/octet-stream'}
  media = MediaFileUpload(path, mimetype='application/octet-stream', resumable=True)
  created = drive_service.files().create(body=file_metadata, media_body=media, fields='id').execute()
  
  return created

save_file_to_drive(file_name, file_name)
				
			

Then, we repeat the same script above to receive the predictions but for the English datasets; df_short_en_f and df_short_en_l as the following:

				
					# sending the request to the Perspective API
# importing time library
import time

# Define a dictionary to store the predicted toxicity probabilities scores
comment_scores = {}
i = 0
# the name of the dataset/ dataframe should be replaced with "df_short_en_l" to analyze the last 200 English tweets
for c in df_short_en_f['tweet']:
  i = i + 1
  data_dict = {
    'comment': {'text': c},
    'languages': ['en'],
    'requestedAttributes': {'TOXICITY': {}}
  }
  response = requests.post(url=url, data=json.dumps(data_dict)) 
  response_dict = json.loads(response.content)
  print (response_dict) 
  comment_scores[c] = response_dict['attributeScores']['TOXICITY']['summaryScore']['value']
  if (i % 10) == 0:
    time.sleep(60)

# tweets textual content is saved in the keys
keys = comment_scores.keys()
# the predicted probabilities scores are saved in values
values = comment_scores.values()

print(comment_scores)
				
			
Samples from the output of the English dataset

We repeat the same steps above to create a dataframe and save the predictions results to a CSV file and upload it to Google drive as the following:

				
					# saving the predictions to a dataframe and then to a CSV file for further analysis
# replace the outputfile name with "Perspective_en_last.csv" to save the predictions for the last 200 English tweets

outputfile = "Perspective_en_first.csv" 
df_Predictions_en_f = pd.DataFrame({'tweet': keys, 'Predicted':values})

with open(outputfile, mode='w', newline='\n', encoding="utf-8-sig") as f:
            df_Predictions_en_f.to_csv(f, sep=',', float_format='%.2f',
                              index=False, quoting=csv.QUOTE_MINIMAL)
                              

# saving the file to your Google drive
# replace the file name with "Perspective_en_last.csv" to save the predictions for the last 200 Arabic tweets to the drive
# you will need to grant permission to Colab to access your Google drive
file_name = "Perspective_en_first.csv" 

from googleapiclient.http import MediaFileUpload
from googleapiclient.discovery import build
from google.colab import auth

auth.authenticate_user()
drive_service = build('drive', 'v3')

def save_file_to_drive(name, path):
  file_metadata = {'name': name, 'mimeType': 'application/octet-stream'}
  media = MediaFileUpload(path, mimetype='application/octet-stream', resumable=True)
  created = drive_service.files().create(body=file_metadata, media_body=media, fields='id').execute()
  
  return created

save_file_to_drive(file_name, file_name)
				
			

Evaluating Samples from the Results:

The datasets used in this exercise are not labelled. We do not have gold labels to check and evaluate the predictions toxicity scores and use the standard performance measures, such as recall, F-1, precision, or accuracy. Thus, we will be very limited in our evaluation and apply only two methods: manual inspection and general descriptive statistics. We encourage the readers to try other methods to better understand the issue and evaluate the accuracy of the outputs. 

Original Tweet Translated Tweet Predictions Output
عُباد البقر مصرّين على حماقتهم وكفرهم ، يجب طرد العمالة الهندية من الهندوس ، ومقاطعة كل منتجاتهم . #إلا_رسول_الله_يامودى
Cow-worshippers insisting on their foolishness and blasphemy, the Hindus Indian workers must be expelled, and all their products must be boycotted. #Except_the_Messenger_of_God_Mudi
0.32
بالله شوفوا ام خبل هذا يعبد بقره ويتمتع في بشر خلق مبشر بالنبوه ياكلون روث البقره تقديسا لها سبحان الله وبحمده #إلا_رسول_الله_يامودى
Look at this foolish. He worships a cow. They eat cows' dung to glory them. Glory be to God and praise be to Him. # Except_the_Messenger_of_God_Mudi
0.29
يا مسلم، احتسب عند الله دفاعك عن جناب المصطفى صلى الله عليه وسلم، ويكفيك هذا شرفا #مقاطعة_المنتجات_الهندية #إلا_رسول_الله_يامودى https://t.co/F8nI1MC929
Muslim, God will reward your defense of the honorable Prophet peace be upon him, and this suffices you for honor #Boycott_Indian_Products #Except_the_Messenger_of_God_Mudi #Except_Rasul Allah_Yamudi https://t.co/F8nI1MC929
0.11
الكويت : متاجر الأغذية تبدأ ب إزالة المنتجات الهندية المعروضة ، اثر التصريحات المسيئة لرسول ﷺ من قبل الحزب الحاكم في الهن
Kuwait: Food stores start removing Indian products on display, following the insulting statements of the Messenger of Allah, peace and blessings be upon him, by the ruling party in India.
0.09

Samples from the predictions scores output from the Arabic tweets

Original Tweet Predictions Output
#Muslims who raze temples face legal action in #Pakistan. The government often rebuilds such temples there. In #India, we rarely see action against the Hindutva groups who demolish #mosques and dargahs. No government bothers to rebuild any razed Muslim religious place.
0.39
Spreading hatred is necessary for survival of #Modi. This butcher can not do anything else except that, and it is very much saleable too. .So the future is bleaker than anyone can imagine #مَنْ_سَبَّ_نَبِیّاً_فَاقْتُلُوْہٗ #إلا_رسول_الله_يا_مودي
0.22
A massive row had erupted across #India after now suspended #BJP leader #NupurSharma ‘insulted’ #ProphetMohammad in a television show recently. #ProphetMuhammad #nupursharmabjp #Mizoram #Christians #Christian https://t.co/Kq0vpa1QhD
0.02
The accused were first brutally beaten up by the villagers, after which they sprinkled kerosene to burn them alive
0.39

Samples from the predictions scores output from the English tweets

A general descriptive statistical information could help to assess the overall outcome of the predictions. The following figures pinpoint if there are any variations among the datasets.

General descriptive statistical results of the first 200 English tweets
General descriptive statistical results of the last 200 English tweets
General descriptive statistical results of the first 200 Arabic tweets
General descriptive statistical results of the last 200 Arabic tweets

Results demonstrate very similar patterns among the two parts of the Arabic dataset. Both Arabic datasets show very low probabilities of toxicity, which reflects that the online conversations regarding this topic is generally clean and use normal language that does not hurt others. The Arabic tweet that received the highest toxicity score, 0.46, is “شوف عمرك كبير بس عقلك عقل مدري ايش حتى حيوان يشهد ان لا إله إلا الله و تجي انت تسب تتوقع انك راح تعيش ماراح تموت يا عابد بقر؟ شوف حتى امكن اكلك فيه بقر والله بقر أطهر منك شوف كل شعرك ابيض على اقل احترم اديان ناس ولا تدخل يا معفن قرف يقرفك ان شاءالله #إلا_رسول_الله_يامودى “/ “Your age is old but your mind does not know what even an animal knows, even the animals know that there is no God but Allah and you come and curse, expecting that you will live forever and never die, you are a cow’s worshiper? Look to your food, even your food might come from cows. I swear cows are purer than you. Look to your white hair, at least respect people’s religions and do not intervene, you are rotten and disgusting  #except_Messenger_of_God_Mudi”. It contains toxic language written in dialectal Arabic and it is related to the topic we are investigating in this experiment.

On the other hand, the results from the two English datasets show some variations among the content of the tweets. The first 200 English tweets contain more toxic language than the last 200 English tweets. The tweets that has the highest toxicity score, 0.73, is ” well, Is sudeep bad? tell him that is wife is fuckable too #lol #lmao Ya’ll know #Anya? Hi!! From #hyderabad .. #Bangalor…”, it does contain toxic language but it is not related to the topic we are investigating and to the Indian government. 

The two parts from each language are merged into one dataframe and then the frequencies of the predicted toxicity scores are counted. Results are presented on the following histograms (scores are converted to percentages rather than probabilities).

English tweets frequencies based on the predicted toxicity scores
Arabic tweets frequencies based on the predicted toxicity scores

Note: Both histograms are using toxicity percentages rather than probabilities

In this article, we briefly illustrate an example to apply the Perspective API to identify toxicity in online conversations. We recommend to increase the dataset size to evaluate the results and the performance of the toxicity model accurately. The entire code and datasets used in this exercise is available on this Github repository. We hope you find this article useful and informative. 

Acknowledgment:

I would like to thank Dr. Alyssa Lees from Google Jigsaw for her support and guidance to use the Perspective API, and for her help in writing the script.

Citation:

For attribution in academic contexts, please cite this work as:

Husain F., “Identifying Toxicity in Arabic Text Using the Perspective API”, The Information Science Lab, 28 June 2022.

References:

Leave a Comment

Your email address will not be published. Required fields are marked *