PyLadies Praha

Vizualizace častých slov ve tweetech

Nyní se pokusme o trochu praktičtější úlohu, při níž si zároveň procvičíš novou datovou strukturu, kterou jsi dnes poprvé potkala — slovníky.
Naším cílem bude vytvořit vizualizaci dat z našeho Twitter účtu, ze které bude patrné, o kterých klíčových slovech nejčastěji tweetujeme. Čím se slovo vyskytuje častěji, tím větší ho v obrázku vykreslíme. Může to vypadat např. takto:
Pro vytvoření takové vizualizace budeme muset
  1. Získat text našich tweetů z timeline.
  2. Rozsekat text tweetů na jednotlivá slova.
  3. Odstranit interpunkci.
  4. Najít klíčová slova (tj. slova začínající na '@' nebo '#').
  5. Spočítat jejich relativní frekvence.
  6. Zobrazit vizualizaci.

Instalace knihoven

Abychom znovu nevynalézali kolo (a skončili včas), použijeme několik knihoven pro usnadnění práce. Aktivuj si virtuální prostředí a nainstaluj si potřebné závislosti
$ python -m pip install jinja2 twitter
Kromě nainstalovaných knihoven budeme potřebovat HTML šablonu pro mrak slov, JavaScriptové knihovny, které v ní mrak vykreslí, nějaké pěkné fonty a ještě jeden Python modul pro komunikaci s Twitterem. Všechno si můžeš stáhnout v jednom zip archivu. Pozor, aby se archiv nerozbalil ještě do podsložky. Jeho obsah potřebujeme přímo ve složce, ve které budeme psát náš Python skript.

Vytvoření Twitter aplikace

Abychom mohli získat data z našeho Twitter účtu, musíme nejdřív v našem účtu vytvořit aplikaci, které dovolíme získat data z naší timeline. Jdi na https://apps.twitter.com a vytvoř novou aplikaci tlačítkem Create New App. Vyplň nějaké jméno, krátký popis a jako Website můžeš dát cokoliv, např. "http://pyladies.example". Callback URL nech prázdnou.
Nás budou zajímat přístupové údaje k této aplikaci. Ty najdeš v nastavení aplikace, kam jsi byla přesměrována po jejím vytvoření, konkrétně v záložce Keys and Access Tokens. Už máme vygenerovaný Consumer Key a Consumer Secret, ale k přihlášení do aplikace je potřeba ještě přístupový token, vytvoř si ho tlačítkem Create Access Token.

Získání dat z Twitteru

S vytvořenou aplikací už budeme schopní získat tweety přímo v Pythonu. Vytvoř si nový Python skript ve složce, kam jsi předtím rozbalila zip archiv. Nejdřív naimportujeme modul pro získání dat z timeline a údaje pro přihlášení ze souboru oauth_info.py.
import twitter_timeline
import oauth_info

Přihlášení k Twitter aplikaci

Data z Twitteru umí vytěžit objekt TimelineMiner, který si vytvoříme takto:
timeline = twitter_timeline.TimelineMiner(
    oauth_info.ACCESS_TOKEN,
    oauth_info.ACCESS_TOKEN_SECRET,
    oauth_info.CONSUMER_KEY,
    oauth_info.CONSUMER_SECRET,
    oauth_info.USER_NAME
)
Nejdříve se musíme do Twitteru přihlásit. To uděláme zavoláním funkce authenticate() na objektu TimelineMiner. Rovnou můžeme vypsat do terminálu, že se přihlášení podařilo.
if timeline.authenticate():
    print('Prihlaseni do Twitteru probehlo uspesne.')
Spusť svůj skript a sleduj, co se stane. Došlo k výjimce — přečti si pozorně popis výjimky. Nastala kvůli tomu, že jsme nepředali TimelineMineru přihlašovací údaje k naší Twitter aplikaci. Otevři si soubor oauth_info.py a doplň tam přihlašovací informace ke své aplikaci. Pozor na to, že tokeny jsou stringy, musí tedy být v uvozovkách. Zkus pustit skript znovu, nyní by již mělo vše proběhnou v pořádku.

Získání textu tweetů

Nyní nám nic nebrání získat samotný text tweetů. Na objektu TimelineMiner zavoláme metodu get_timeline() a tím se nám tweety stáhnou.
timeline.get_timeline(max=2000)
Atribut timeline objektu tweets nyní obsahuje seznam našich tweetů. Pro pohodlnější práci si je spojíme do jednoho řetězce.
text = ' '.join(timeline.tweets)

Odstranění interpunkce

Aby byla vizualizace vypovídající, musíme provést alespoň drobnou normalizaci dat. Např. nechceme, aby program bral slovo s tečkou na konci a bez tečky jako 2 různá slova ("pes" a "pes," jsou vlastně stejná slova). Zkus proto navrhnout funkci odstran_interpunkci, která bude mít jeden argument (řetězec) a vracet bude tentýž řetězec jen s odstraněnou interpunkcí.
Drobná nápověda:
  • Znaky interpunkce jsou v Pythonu dostupné v knihovně string jako string.punctuation.
  • Všechny výskyty znaku x můžeš v řetězci odstranit funkcí retezec.replace('x', '').
  • "@" a "#" jsou sice také interpunkční znaky, ale my je budeme potřebovat, jelikož jimi Twitter značí klíčová slova. Navrhni tedy funkci tak, aby tyto znaky v textu zůstaly.

Řešení

import string

def odstran_interpunkci(retezec):
    znaky_interpunkce = string.punctuation.replace('#', '').replace('@', '')
    for znak in znaky_interpunkce:
        retezec = retezec.replace(znak, '')
    return retezec

Získání klíčových slov

V textu bývá mnoho nezajímavých slov jako jsou spojky nebo běžná podstatná jména a slovesa. Ty by měly četnost větší než cokoliv zajímavého. Pracujeme ale s daty z Twitteru, kde jsou jasně označena klíčová slova ("#hashtag") a účty jiných uživatelů ("@uzivatel"). Elegantně se zbavíme problému s běžnými slovy tím, že budeme brát v úvahy jen tato zvýrazněná slova.
Navrhni tedy funkci najdi_klicova_slova, která bere řetězec a vrátí seznam slov začínajících na "@" nebo "#".
Nápověda:
  • Řetězec můžeš rozsekat na seznam jednotlivých slov funkcí retezec.split().
  • Otestovat, zda jeden řetězec začíná na jiný můžeme funkcí retezec.startswith('bla').

Řešení

def najdi_klicova_slova(text):
    klicova_slova = []
    for slovo in text.split():
        if slovo.startswith('#') or slovo.startswith('@'):
            klicova_slova.append(slovo.lower())
    return klicova_slova

Spočítání frekvence slov

Teď trocha matematiky. Abychom věděli, která slova mají být v mraku větší, potřebujeme znát relativní frekvence všech slov. Na spočítání výskytu nějakého slova je ideální datovou strukturou slovník.
Navrhni funkci spocitej_frekvence, která dostane seznam slov a vrátí slovník, ve kterém bude vždy klíčem dané slovo a hodnotou jeho relativní frekvence.
Nápověda:
  • Nejdřív si do slovníku nasčítej počet výskytů každého jednoho slova, teprve pak slovník projdi v cyklu a poděl počet výskytů slova celkovým počtem slov.
  • Nezapomeň, že pokud chceš procházet v cyklu dvojice klíč-hodnota, musíš na slovníku zavolat funkci slovnik.items()

Řešení

def spocitej_frekvence(slova):
    # Napocitej vyskyt kazdeho slova
    frekvence_slov = {}
    for slovo in slova:
        if slovo in frekvence_slov.keys():
            frekvence_slov[slovo] += 1
        else:
            frekvence_slov[slovo] = 1

    # Spocitej relativni frekvenci
    for slovo, frekvence in frekvence_slov.items():
        frekvence_slov[slovo] /= len(slova)

    return frekvence_slov

Vykreslení mraku slov

Nyní už máme všechna data, která potřebujeme k vykreslení mraku slov. K tomu použijeme modul Jinja2, který do připravené šablony nasype z Pythonu slova a jejich frekvence a vytvoří z šablony běžnou HTML stránku. O vykreslení mraku se už v prohlížeči postará JavaScriptová knihovna d3. Nemáme čas vyložit Jinju detailněji, ale je to spíš implementační detail, který není až tak důležitý. Směle zkopíruj následující kód, ale prohlédni si ho a přečti si pozorně komentáře.
import json

loader = jinja2.FileSystemLoader(searchpath='./')  # Kde ma Jinja2 hledat sablony?
env = jinja2.environment.Environment(loader=loader)  # Inicializuj Jinja2 prostredi
frekvence_json = json.dumps(frekvence_slov)  # Preved slovnik do formatu, kteremu rozumi JavaScript
template = env.get_template('wordcloud.jinja2')  # Nacti pripravenou sablonu

# Priprav data pro sablonu
template_data = {
    'words': frekvence_json,
    'width': 1200,  # Sirka mraku
    'height': 1200,  # Vyska mraku
    'rescale': 1500  # Jake rozpeti velikosti ma byt mezi slovy?
}

# Vykresli HTML stranku a uloz do souboru
with open('wordcloud.html', 'w') as result_file:
    result_file.write(template.render(template_data))                       
Nyní bys už měla mít ve složce nový soubor wordcloud.html. Otevři ho a podívej se, o čem a o kom nejčastěji tweetuješ!

Rozšíření: Odstranění málo častých slov

Pokud máš tweetů hodně, možná je mrak dost nepřehledný a plný skoro nečitelných, a tedy málo častých slov. Aby byla vizualizace přehlednější, je rozumné zahodit málo častá slova.
Navrhni funkci odstran_malo_casta, která dostane slovník relativních frekvencí a vrátí slovník obsahující pouze slova s častějším výskytem.
Nápověda:
  • Raději než odstraňovat slova s malou frekvencí zkonstruuj slovník nový, který bude obsahovat jen častější slova, např. s četností větší než je 1/20 četnosti slova s maximální četností.
  • Maximum ze seznamu hodnot získáš vestavěnou funkcí max(seznam).

Řešení

def odstran_malo_casta(frekvence_slov):
    caste = {}
    for slovo, frekvence in frekvence_slov.items():
        if frekvence > max(frekvence_slov.values()) / 20:
            caste[slovo] = frekvence
    return caste