Back-End

25 jun, 2014

Gol! Usando um Raspberry Pi para detectar os melhores momentos da Copa no Twitter

1128 visualizações
Publicidade

Os jogos da Copa do Mundo são assistidos por bilhões de pessoas no mundo todo. E assim como qualquer evento esportivo, fãs usam o Twitter para falar sobre o jogo, torcer pelo seu time e conversar com amigos e até usuários fora do seu grafo social. É comum também que esses fãs narrem eventos importantes do jogo, especialmente quando um gol é feito.

Nós organizamos o Hackathon da Taça, realizado em São Paulo, no fim de maio. Entre auxiliar os times nas suas integrações e ajudar a organizar o evento como um todo, eu decidi brincar um pouco com um Raspberry Pi e a API de Streaming do Twitter. A ideia era construir um alerta de gol que tocaria toda vez que o volume de tweets sobre um determinado gol da Copa aumentasse inesperadamente. Para atingir meu objetivo, eu precisei fazer o seguinte:

  • Conectar na API de streaming do Twitter para calcular a frequência de tweets mencionando um gol;
  • Criar um dispositivo que tocaria um sino toda vez que houvesse um aumento rápido na magnitude (um spike) dessa frequência.

Spoiler alert! Se você está curioso para saber como eu construí o sino antes de ler as especificações, dê uma olhada no Vine abaixo:

Detectando spikes no volume de tweets

Detectar eventos relevantes em dados de séries temporais não é algo de outro mundo e você pode encontrar vários artigos sobre esse assunto. Porém, às vezes, a implementação dessas técnicas é bastante complexa para ser aplicadas em um curto espaço de tempo. Eu decidi construir uma abordagem mais simples, porém menos precisa e que funcionaria bem para os requisitos desse projeto. Parti da hipótese que durante um determinado jogo, vários fãs criariam tweets quando um gol fosse feito. Algumas simulações que fiz mais tarde confirmaram que esse pulso pode ser facilmente detectado.

Dê uma olhada nos dados abaixo, extraídos do segundo tempo do jogo de estréia da Copa do Mundo, entre Brasil e Croácia:

art02
Imagem 1: Tweets por segundo mencionando “gol copa, gool copa, goool, golaço” durante o jogo de 12 de Junho de 2014.

Para capturar esses dados, eu simplesmente conectei no endpoint POST status/filter da API de Streaming do Twitter. Nessa conexão eu monitorei todas as menções à gols em Português Brasileiro, combinadas com menções à Copa e suas variações. Cada Tweet retornado pela conexão era usado para calcular a frequência de tweets por segundo (TPS). Basta olhar no gráfico acima para facilmente identificar quando que os gols ocorreram (o pênalti do Neymar e o gol do Oscar).

O próximo passo foi converter esses dados com bastante ruído para um valor de base que poderia servir como um gatilho para tocar o sino quando um determinado nível pré-estabelecido fosse atingido. Para esse caso, usei uma simples ferramenta estatística: a média móvel exponencial (EMA). Ao invés de mostrar as fórmulas, vamos visualizar o que a aplicação do EMA faz com os dados:

Imagem 2: EMA calculado com base nos Tweets por segundo relativo ao primeiro gol do segundo tempo de Brasil versus Croácia (o pênalti do Neymar).
Imagem 2: EMA calculado com base nos Tweets por segundo relativo ao primeiro gol do segundo tempo de Brasil versus Croácia (o pênalti do Neymar).

Como você pôde visualizar, a aplicação da média móvel exponencial atenua os ruídos gerados pela frequência de tweets por segundo e nos dá uma visão mais clara sobre os dados. Isso evita a geração de falsos positivos, caso em um momento específico haja um volume bem maior de tweets, mas sem a relação com um evento como um gol. A partir disso eu simplesmente calculo o crescimento que há entre a hora atual e 10 segundos atrás: (EMA agora – EMA 10 seg atrás) / EMA 10 seg atrás. Vamos visualizar os resultados deste cálculo no mesmo período acima para entender de que forma que ele nos ajuda a ter um valor base para o nosso gatilho do sino:

Imagem 3: Detecção do Spike usando o crescimento (growth) relativo durante o primeiro gol do segundo tempo de Brasil e Croácia. A linha amarela mostra o nível (threshold) que deve ser ultrapassado para que o sino toque.
Imagem 3: Detecção do Spike usando o crescimento (growth) relativo durante o primeiro gol do segundo tempo de Brasil e Croácia. A linha amarela mostra o nível (threshold) que deve ser ultrapassado para que o sino toque.

Quando os cálculos do crescimento relativo são maiores do que 1.5 (o que significa que houve um crescimento de 150% nos tweets por segundo entre o agora e 10 segundos atrás) o algoritmo dispara o gatilho que toca o sino notificando o gol. Vamos visualizar somente o crescimento relativo de todo o segundo tempo do jogo, removendo a curva com a média móvel exponencial:

Imagem 4: Detecção do Spike usando o crescimento (growth) relativo durante o primeiro gol do segundo tempo de Brasil e Croácia. Sim, tivemos dois gols nesse período.
Imagem 4: Detecção do Spike usando o crescimento (growth) relativo durante o primeiro gol do segundo tempo de Brasil e Croácia. Sim, tivemos dois gols nesse período.

É interessante tentar analisar por que o primeiro gol teve um crescimento muito maior. Na minha opinião, os usuários de Twitter já estavam preparados para criar tweets assim que o Neymar fizesse o gol, uma vez que foi um pênalti. Isso resultou em mais pessoas criando tweets em um curto espaço de tempo.

Como você pode ver também no último gráfico, a forma como calculamos o crescimento relativo nos ajudou a identificar como um gol somente quando a frequência de tweets por segundo variou de forma rápida e com uma amplitude significativa, isto é, quando um evento realmente emocionante aconteceu durante o jogo.

Fiz implementações desses cálculos em Python e Ruby para você que quer experimentar nos outros jogos da Copa ou em outras situações. O código para conectar na API de Streaming é relativamente curto e simples: https://github.com/lfcipriani/tilingol/blob/master/tilingol.rb#L40

@client = TweetStream::Client.new

@client.on_error do |message|
  puts "ERROR: #{message}"
end


puts "Starting to track: #{@keywords}...\nLanguages: #{@languages}"
@client.filter(:track => @keywords, :language => @languages) do |status|
  @peak_detector.collect_frequency
  @bell.ring! if @peak_detector.is_this_a_peak?
end

Você também pode fazer o download dos dados que foram capturados durante o jogo Brasil e Croácia, caso você queira plotá-los de maneira diferente.

Tocando o sino (pequenino)

Uma vez tendo o algoritmo de detecção de gols implementado, o seu dispositivo deve tocar o sino para notificar que houve o gol. Eu decidi usar um Raspberry Pi para isso. Essa foi a primeira vez que eu brinquei com um e o potencial dessa maquininha é incrível. Eu fiz o sistema de alerta com materiais que eu trouxe de casa e emprestei outros de amigos que estavam no Hackathon. Aqui está a lista de materiais e uma breve explicação de como cada item foi usado:

  • Raspberry Pi rev 2: é a unidade computacional que executou a conexão com a API de Streaming, detectou os spikes e controlou o acionamento do sino;
  • Servo motor: Um pequeno motor com controle preciso de posição, velocidade e aceleração. Foi usado para sacudir os sininhos;
  • Jumper wires: São pequenos fios que você usa para conectar o Raspberry Pi com o motor;
  • Sininhos de natal: Uma adequada maneira de identificar um emocionante gol;
  • Palitinho de café: Usado para aumentar a amplitude de movimento do Servo motor, o que significa mais barulho;
  • Clips de papel: Para segurar os sininhos;
  • Blocos de Lego: Usados para construir a estrutura que segura o motor e o Raspberry Pi – sem falar que deixa o projeto bem mais legal.

Segue uma representação gráfica das conexões, que são bem simples:

Imagem 5: Esquema do projeto de hardware. Não me responsabilizo por acidentes causados por esse esquema.
Imagem 5: Esquema do projeto de hardware. Não me responsabilizo por acidentes causados por esse esquema.

O código que ativa a pinagem e faz os sinos sacudirem está abaixo: https://github.com/lfcipriani/tilingol/blob/master/jinglebells.py

import RPi.GPIO as GPIO
import time
import sys

class JingleBells:

    def __init__(self, pin):
        self.pin = pin
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(self.pin, GPIO.OUT)

    def shake(self, iterations, speed):
        self.pwm = GPIO.PWM(self.pin, 100)
        self.pwm.start(19)
        time.sleep(speed)
        for n in range(iterations):
            self.pwm.ChangeDutyCycle(16)
            time.sleep(speed)
            self.pwm.ChangeDutyCycle(19)
            time.sleep(speed)
        self.pwm.stop()

if __name__ == '__main__':
    jb = JingleBells(18)
    jb.shake(int(sys.argv[1]), float(sys.argv[2]))
    GPIO.cleanup()
    exit()

Você só precisa executar esse arquivo Python e decidir quantas vezes o sino deve sacudir (parâmetro iterations) e em qual velocidade (parâmetro speed). Daí basta você chamar esse programa a partir do algoritmo de detecção de gols que implementamos anteriormente. Um detalhe importante é chamá-lo de forma assíncrona, pois nós não queremos enfileirar o fluxo de tweets vindo pela conexão de streaming, isso pode causar erros na execução (veja https://github.com/lfcipriani/tilingol/blob/master/jingle_bell.rb).

Está fora do escopo desse artigo explicar o que é PWM e como usar a biblioteca GPIO, mas saiba que há vários bons recursos que ensinam esses detalhes no site do Rasperry Pi.

Conclusão

Nós demonstramos com esse artigo como é fácil detectar gols baseado no volume de tweets vindo a partir de uma conexão com a API de streaming do Twitter. Após identificar esses gols, você pode decidir a melhor maneira de notificar alguém de que ele aconteceu… Mas devo dizer, usar um Raspberry Pi para isso e um monte de sininhos de natal é uma maneira bem divertida de fazê-lo. Quando falamos sobre a plataforma do Twitter, nós sempre comentamos que a API é um ótimo recurso para conectar no pulso do planeta. Eu espero que com esse artigo eu tenha convencido de que esse pulso realmente existe.

Todo o código construído para fazer isso acontecer está disponível no Github. Gostaria também de agradecer ao @luisleao pela ajuda na parte do hardware desse projeto e também por emprestar alguns materiais imprescindíveis.

Compartillhe também os seus projetos usando a plataforma do Twitter com o @TwitterDevBr. Esse artigo também foi publicado em inglês no blog de desenvolvedores do Twitter.