[PROJETO] Analisando Posts do Hacker News
Tags: python, analytics, beginners, programming
Published: 2022-03-04 19:50:12

Todo o conteúdo deste projeto pode ser encontrado no meu repositório do GitHub. Para mais detalhes, [acesse o link](https://github.com/lis-r-barreto/Data-Engineering-Portfolio).

## **Introdução**

O Hacker News é um site iniciado pela incubadora de startups [Y Combinator](https://www.ycombinator.com/), onde as histórias enviadas por usuários (conhecidas como "posts") são votadas e comentadas, semelhante ao reddit. O Hacker News é extremamente popular nos círculos de tecnologia e startups, e as postagens que chegam ao topo das listagens do Hacker News podem receber centenas de milhares de visitantes como resultado.

<p align="center">
  <img src="https://miro.medium.com/max/700/1*CVOGx9ckrpWyTvtQgauYpw.jpeg" width="300" >
</p>

## **Objetivo**
Estamos especificamente interessados ​​em postagens cujos títulos começam com Ask HN ou Show HN. Os usuários enviam postagens Ask HN para fazer uma pergunta específica à comunidade Hacker News. Abaixo segue um exemplo:

*Ask HN: Como melhorar meu site pessoal?*

Da mesma forma, os usuários enviam postagens do Show HN para mostrar à comunidade do Hacker News um projeto, produto ou apenas algo interessante. Abaixo segue um exemplo:

*Show HN: Plataforma de desenvolvimento de hardware baseada em Wio Link ESP8266 Web of Things'*

Compararemos esses dois tipos de postagens para determinar o seguinte:
- Em média, quais postagens recebem mais comentários? Os posts cujos títulos começam com Ask HN ou Show HN?
- Em média, qual horário recebe uma quantidade maior de comentários?

## **Abrindo e explorando os dados**

Você pode encontrar o conjunto de dados [aqui](https://www.kaggle.com/hacker-news/hacker-news-posts), mas observe que ele foi reduzido de quase 300.000 linhas para aproximadamente 20.000 linhas removendo todos os envios que não recebeu nenhum comentário e, em seguida, amostragem aleatória das submissões restantes.

Abaixo estão as descrições das colunas:
- id: O identificador exclusivo do Hacker News para a postagem
- título: O título do post
- url: o URL para o qual as postagens são vinculadas, se a postagem tiver uma URL
- num_points: o número de pontos que o post adquiriu, calculado como o número total de votos positivos menos o número total de votos negativos
- num_comments: O número de comentários que foram feitos no post
- autor: o nome de usuário da pessoa que enviou a postagem
- created_at: A data e hora em que a postagem foi enviada


Vamos começar importando as bibliotecas que precisamos e lendo o conjunto de dados em uma lista de listas e explorando as primeiras 5 linhas.

```python
from csv import reader

opened_file = open ('hacker_news.csv',encoding = 'utf8')
read_file = reader (opened_file)
hn = list (read_file)

for row in hn[:5]:
    print (row)
    print('\n')
```

Observe que a primeira lista nas listas internas contém os cabeçalhos das colunas e as listas posteriores contêm os dados de uma linha. Para analisar nossos dados, precisamos primeiro remover a linha que contém os cabeçalhos das colunas. Vamos remover essa primeira linha.

```python
headers = hn[0]  #Não execute esta célula mais de uma vez
hn = hn[1:]

print (headers)
print('\n')
for row in hn[:5]:
    print (row)
    print('\n')
```

Agora que removemos os cabeçalhos de hn, estamos prontos para filtrar nossos dados. Como estamos preocupados apenas com títulos de postagem que começam com **Ask HN** ou **Show HN**, criaremos novas listas de listas contendo apenas os dados desses títulos.

## **Classificando os dados**

Para encontrar as postagens que começam com Ask HN ou Show HN (e variações de maiúsculas e minúsculas), usaremos o método string `startswith` e verificaremos os dados imprimindo cinco linhas de cada lista.

```python
ask_posts = []
show_posts = []
other_posts = []

for row in hn:
    title = row[1]
    title_lower = title.lower()
    
    if title_lower.startswith('ask hn'):
        ask_posts.append(row)
    
    elif title_lower.startswith('show hn'):
        show_posts.append(row)
        
    else:
        other_posts.append(row)
        
for row in ask_posts[:5]:
    print (row)
    print('\n')
print('\n')
for row in show_posts[:5]:
    print (row)
    print('\n')
print('\n')
for row in other_posts[:5]:
    print (row)
    print('\n')
print('Número de posts Ask HN:',len(ask_posts))
print('Número de posts Show HN:',len(show_posts))
print('Número de outros posts:',len(other_posts))
```
Em seguida, vamos determinar se as postagens de perguntas ou de exibição recebem mais comentários em média.

```python
total_ask_comments = 0

for row in ask_posts:
    total_ask_comments +=  int(row[4])
    
avg_ask_comments = total_ask_comments / len (ask_posts)

total_show_comments = 0

for row in show_posts:
    total_show_comments +=  int(row[4])
    
avg_show_comments = total_show_comments / len (show_posts)

print('Número médio de comentários Ask HN:',avg_ask_comments)
print('Número médio de comentários Show HN:',avg_show_comments)
```

## **Reformatando e analisando os dados**

Fica claro que, em média, os posts de pergunta recebem mais comentários do que os posts de exibição. Como as postagens de perguntas são mais propensas a receber comentários, focaremos nossa análise restante apenas nessas postagens.

Em seguida, determinaremos se as postagens de perguntas criadas em um determinado momento são mais propensas a atrair comentários. Usaremos as seguintes etapas para realizar essa análise:

1. Calcular a quantidade de posts Ask HN criados em cada hora do dia, juntamente com o número de comentários recebidos.
2. Calcular o número médio de comentários que as postagens de solicitação recebem por hora de criação.

Usaremos o módulo `datetime` para trabalhar com os dados na coluna ` created_at` para calcular a quantidade de postagens e comentários de perguntas por hora criados.

```python
import datetime as dt

result_list = []

for row in ask_posts:
    result_list.append ( [ row[6] , int(row[4]) ] )
    
counts_by_hour = {}
comments_by_hour = {}

for row in result_list:
    time_created = dt.datetime.strptime(row[0],'%m/%d/%Y %H:%M')
    hour = time_created.hour
    
    if hour not in counts_by_hour:
        counts_by_hour[hour] = 1
        comments_by_hour[hour] = row[1]
    else:
        counts_by_hour[hour] += 1
        comments_by_hour[hour] += row[1]

print('O número de postagens de perguntas criadas durante cada hora do dia:')
print(counts_by_hour)
print('\n')
print('O número correspondente de comentários criados a cada hora recebida:')
print(comments_by_hour)
```
Em seguida, usaremos esses dois dicionários para calcular o número médio de comentários para postagens criadas durante cada hora do dia, criando uma lista de listas contendo as horas em que as postagens foram criadas e o número médio de comentários que essas postagens receberam.

```python
avg_by_hour = []

for hour in counts_by_hour:
    no_of_posts = counts_by_hour[hour]
    no_of_comments = comments_by_hour[hour]
    avg_no_comments = comments_by_hour[hour] / counts_by_hour[hour] 
    avg_by_hour.append([hour,avg_no_comments])
    
print(avg_by_hour)
```
Agora vamos classificar os dados acima em ordem decrescente do número médio de comentários para facilitar a análise.

```python
swap_avg_by_hour = []

for value in avg_by_hour:
    swap_avg_by_hour.append([value[1],value[0]])
    
sorted_swap = sorted(swap_avg_by_hour,reverse = True)

print('Os 5 horários com maior numéro médio de comentários por postagens do Ask HN')
print('\n')

for row in sorted_swap:
    template = '{time}:00: {num:.2f} média de comentários por post.'
    print(template.format(time = row[1] , num = row[0]))
```

## **Conclusões**

- As postagens de perguntas têm um número médio de comentários mais alto do que as postagens de exibição.
- O horário de 15:00 GMT tem o maior número médio de comentários.


## **Referências**

**Este projeto guiado faz parte do [*Data Enginnering Carreer Path*](https://www.dataquest.io/path/data-engineer/) proposto pela**
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6iq3cl7ceknfm116uch.png)