PySpark: uma breve análise das palavras mais comuns em Drácula, por Bram Stoker
Tags: python, dataengineering, spark, datascience
Published: 2022-09-24 16:24:46

> Note: dis article is also available in [english](https://dev.to/geazi_anc/pyspark-a-brief-analysis-to-the-most-common-words-in-dracula-by-bram-stoker-1ij4) 🌎.

Considerado como um marco da literatura gótica, o icônico livro Drácula, escrito em 1897 por Bram Stoker, desperta até hoje o fascínio das pessoas por todo o mundo. Hoje, a fim de introduzir novos conceitos e funcionalidades do Apache Spark, vamos desenvolver uma breve análise das palavras mais comuns encontradas neste clássico livro 🧛🏼‍♂️.

Para isso, vamos desenvolver um notebook no [Google Colab](https://colab.research.google.com/), um serviço de nuvem gratuito criado pelo Google para incentivar pesquisas na área de machine learning e inteligência artificial.

Caso não saiba como usar o Google Colab, confira [este excelente artigo](https://www.alura.com.br/artigos/google-colab-o-que-e-e-como-usar) da Alura escrito pelo Thiago Santos que ensina, de forma muito didática, como usar o Colab e criar seus primeiros códigos!

O notebook deste artigo também está disponível em meu [GitHub](https://github.com/geazi-anc/dracula) 😉.

A obra em questão foi obtida por meio do [Projeto Gutenberg](https://www.gutenberg.org/), um acervo digital que reúne livros de todo o mundo que já se encontram em domínio público. A versão plaintext de Drácula pode ser baixada gratuitamente [aqui](https://www.gutenberg.org/cache/epub/345/pg345.txt).

## Antes de começar

Antes de iniciarmos o desenvolvimento de nosso notebook, é necessário fazer a instalação da biblioteca [PySpark](https://spark.apache.org/docs/latest/api/python/index.html).

A biblioteca PySpark é a API oficial do Python para o Apache Spark. É com ela que vamos realizar nossa análise de dados 🎲.

Crie uma nova célula de código no Colab e execute a seguinte linha:

```
!pip install pyspark
```

## Passo um: inicialização do Apache Spark

Logo após a instalação, precisamos inicializar o Apache Spark. Para isso, crie uma nova célula de código no Colab e adicione o seguinte bloco:

```
         from pyspark.sql import SparkSession


spark = (SparkSession.builder
         .appName("The top most common words in Dracula, by Bram Stoker")
         .getOrCreate()
         )
```

## Passo dois: download e leitura de Drácula, por Bram Stoker

Agora sim podemos começar! Nesta etapa iremos fazer o download do livro Drácula do projeto Gutenberg e, logo em seguida, fazer a leitura do arquivo através do PySpark.

O download do livro consiste, basicamente, no uso do utilitário **wget**, informando a URL que direciona para o livro Drácula no projeto Gutenberg. Depois, salva-se o conteúdo da solicitação, isto é, o próprio livro, no diretório atual, com o nome de **Dracula – Bram Stoker.txt**.

Crie uma nova célula no colab e adicione o seguinte bloco de código:

```
!wget https: // www.gutenberg.org/cache/epub/345/pg345.txt -O "Dracula - Bram Stoker.txt"
```

## Passo três: download das stopwords em inglês

A seguir, iremos fazer o download de uma lista das stopwords que são frequentemente usadas no idioma inglês. Essas stopwords normalmente incluem preposições, partículas, interjeições, uniões, advérbios, pronomes, palavras introdutórias, números de 0 a 9 ( inequívocos ), outras partes oficiais da fala, símbolos, pontuação. Recentemente, essa lista foi complementada por sequências de símbolos comumente usadas na Internet como www, com, http, etc.

Essa lista foi adquirida através do site [CountWordsFree](https://countwordsfree.com/stopwords), um site que, dentre outros utillitários, reúne as stopwords encontradas em diversos idiomas, incluindo o nosso querido português.

Mãos a obra! Crie uma nova célula de código e adicione o seguinte bloco:

```
!wget https://countwordsfree.com/stopwords/english/txt -O "stop_words_english.txt"
```

Feito esses downloads, podemos fazer a leitura do livro através do PySpark. Crie uma nova célula no Colab e adicione o seguinte bloco de código:

```
book = spark.read.text("Dracula - Bram Stoker.txt")
```

E também vamos fazer a leitura das stopwords que acabamos de baixar. As stopwords serão armazenadas em uma lista, na variável **stopwords**.

```
with open("stop_words_english.txt", "r") as f:
    text = f.read()
    stopwords = text.splitlines()

len(stopwords), stopwords[:15]
```

**Output**

```
(851,
 ['able',
  'about',
  'above',
  'abroad',
  'according',
  'accordingly',
  'across',
  'actually',
  'adj',
  'after',
  'afterwards',
  'again',
  'against',
  'ago',
  'ahead'])
```

## Passo quatro: Extração individual das palavras

Após a leitura do livro, é necessário que transformemos cada uma das palavras em uma coluna no DataFrame.

Para isso, utiliza-se o método **split**, o qual, para cada uma das linhas, irá separar cada uma das palavras através do espaço em branco entre elas. O resultado será uma lista de palavras.

```
from pyspark.sql.functions import split


lines = book.select(split(book.value, " ").alias("line"))
lines.show(5)
```

**Output**:

```
+--------------------+
|                line|
+--------------------+
|[The, Project, Gu...|
|                  []|
|[This, eBook, is,...|
|[most, other, par...|
|[whatsoever., You...|
+--------------------+
only showing top 5 rows
```

## Passo cinco: explodindo a lista de palavras em colunas no DataFrame

Depois das palavras terem sido separadas, é necessário que se faça a conversão desta lista de palavras em colunas no DataFrame.

Para tal, usa-se o método **explode** presente no Apache Spark.

```
from pyspark.sql.functions import explode, col


words = lines.select(explode(col("line")).alias("word"))
words.show(15)
```

**Output**

```
+---------+
|     word|
+---------+
|      The|
|  Project|
|Gutenberg|
|    eBook|
|       of|
| Dracula,|
|       by|
|     Bram|
|   Stoker|
|         |
|     This|
|    eBook|
|       is|
|      for|
|      the|
+---------+
only showing top 15 rows
```

## Passo seis: transformando todas as palavras em minúsculas

Esta é uma etapa bem simples. Para que não haja distinção da mesma palavra por conta de letras maiúsculas, vamos transformar todas as palavras no DataFrame para letras minúsculas, fazendo o uso da função **lower**.

```
from pyspark.sql.functions import lower


words_lower = words.select(lower(col("word")).alias("word_lower"))
words_lower.show()
```

**Output**

```
+----------+
|word_lower|
+----------+
|       the|
|   project|
| gutenberg|
|     ebook|
|        of|
|  dracula,|
|        by|
|      bram|
|    stoker|
|          |
|      this|
|     ebook|
|        is|
|       for|
|       the|
|       use|
|        of|
|    anyone|
|  anywhere|
|        in|
+----------+
only showing top 20 rows
```

## Passo sete: eliminação de pontuação

Para que também não haja distinção da mesma palavra por conta da pontuação presente no final delas, é preciso removê-las.

Isso é feito através do método **regexp_extract**, o qual extrai palavras de uma string por meio de uma expressão regular.

Calma, não precisa se assustar! A expressão é bem simples. Ela consiste em um conjunto contendo todos os símbolos de A a Z, uma ou mais vezes. Viu, eu te disse que era bem simples 👏🏼.

```
from pyspark.sql.functions import regexp_extract


words_clean = words_lower.select(
    regexp_extract(col("word_lower"), "[a-z]+", 0).alias("word")
)

words_clean.show()
```

**Output**

```
+---------+
|     word|
+---------+
|      the|
|  project|
|gutenberg|
|    ebook|
|       of|
|  dracula|
|       by|
|     bram|
|   stoker|
|         |
|     this|
|    ebook|
|       is|
|      for|
|      the|
|      use|
|       of|
|   anyone|
| anywhere|
|       in|
+---------+
only showing top 20 rows
```

## Passo oito: remoção de valores nulos

Como visto, mesmo após a remoção das pontuações ainda há colunas com valores nulos, ou seja, espaços em branco.

Para que esses espaços em branco não sejam considerados na análise da frequência de cada palavra presente no livro, é necessário removê-los.

```
words_nonull = words_clean.filter(col("word") != "")
words_nonull.show()
```

**Output**

```
+---------+
|     word|
+---------+
|      the|
|  project|
|gutenberg|
|    ebook|
|       of|
|  dracula|
|       by|
|     bram|
|   stoker|
|     this|
|    ebook|
|       is|
|      for|
|      the|
|      use|
|       of|
|   anyone|
| anywhere|
|       in|
|      the|
+---------+
only showing top 20 rows
```

## Passo nove: remoção das stopwords

Estamos quase lá! Antes de partirmos para a análise das palavras mais comuns propriamente dita, precisamos remover as stopwords de nosso dataframe, para que elas não sejam levadas em consideração durante a análise.

```
words_without_stopwords = words_nonull.filter(
    ~words_nonull.word.isin(stopwords))


words_count_before_removing = words_nonull.count()
words_count_after_removing = words_without_stopwords.count()

words_count_before_removing, words_count_after_removing
```

**Output**

```
(163399, 50222)
```

## Passo dez: análise das palavras mais comuns

E, finalmente, chegamos ao fim da limpesa de nossos dados. Agora sim podemos começar a análise das palavras mais comuns presentes no livro.

Primeiro, é realizado a contagem das palavras mais frequentes no dataframe. Para isso, vamos agrupar cada uma das palavras e depois vamos usar uma função de agregação, **count**, para determinar quantas vezes elas aparecem.

```
words_count = (words_without_stopwords.groupby("word")
               .count()
               .orderBy("count", ascending=False)
               )
```

Depois, vamos exibir as 20 palavras mais comuns. O ranque pode ser ajustado através da variável **rank**. Sinta-se à vontade para ajustar a variável como preferir.

```
rank = 20
words_count.show(rank)
```

**Output**

```
+--------+-----+
|    word|count|
+--------+-----+
|    time|  381|
| helsing|  323|
|     van|  322|
|    lucy|  297|
|    good|  256|
|     man|  255|
|    mina|  240|
|    dear|  224|
|   night|  224|
|    hand|  209|
|    room|  207|
|    face|  206|
|jonathan|  206|
|   count|  197|
|    door|  197|
|   sleep|  192|
|    poor|  191|
|    eyes|  188|
|    work|  188|
|      dr|  187|
+--------+-----+
only showing top 20 rows
```

## Considerações finais

É isso por hoje, pessoal. Chegamos no fim de nossa breve análise.

Neste artigo, analisamos as palavras mais comuns do livro Drácula, por Bram Stoker. Para isso, foi necessário fazer uma limpesa nos dados, como dividir as palavras pelos espaços entre elas; explodir a lista de palavras em colunas no dataframe; transformar todas as letras em minúsculas; remover a pontuação de todo o texto através de uma expressão regular; e, por fim, remover as stopwords.

Espero que tenham gostado. Mantenham as estacas afiadas, cuidado com as sombras que andam pela noite, e até a próxima 🧛🏼‍♂️🍷.

## Referências

RIOUX, Jonathan. [Data Analysis with Python and PySpark](https://www.amazon.com.br/Analysis-Python-PySpark-Jonathan-Rioux/dp/1617297208).

STOKER, Bram. [Dracula](https://www.gutenberg.org/cache/epub/345/pg345.txt).