Základní syntaxe Pythonu pro datovou vědu (základy)
Posledních pár dní jsem se díval na knihu Data Science from Scrach (PDF ke stažení zde). Je to skvělá a srozumitelná úvodní kniha do datové vědy. Jedna z kapitol se věnuje základní syntaxi Pythonu a pokročilým konstrukcím často používaným v datové vědě. Přišlo mi to skvěle a stručně vysvětlené, a tak jsem se rozhodl to přeložit a uložit sem jako poznámky pro sebe.
Běžná syntaxe Pythonu v datové vědě (základy)
Běžná syntaxe Pythonu v datové vědě (pokročilé)
Tato kapitola se zaměřuje na představení základní syntaxe a funkcí Pythonu, které jsou velmi užitečné při zpracování dat (založeno na Pythonu 2.7).
Formátování odsazení
Mnoho jazyků používá pro řízení bloků kódu závorky, ale Python spoléhá na odsazení:
for i in [1, 2, 3, 4, 5]:
print i # První řádek cyklu "for i"
for j in [1, 2, 3, 4, 5]:
print j # První řádek cyklu "for j"
print i + j # Poslední řádek cyklu "for j"
print i # Poslední řádek cyklu "for i"
print "done looping"
Díky tomu je kód v Pythonu velmi čitelný, ale zároveň to znamená, že si musíte neustále hlídat formátování. Mezery uvnitř závorek jsou ignorovány, což je užitečné při psaní dlouhých výrazů:
long_winded_computation = (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20)
A také to zlepšuje čitelnost kódu:
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
easier_to_read_list_of_lists = [ [1, 2, 3],
[4 ,5 ,6 ],
[7 ,8 ,9 ] ]
Víceřádkové příkazy
Pro rozdělení příkazu do dvou řádků lze použít zpětné lomítko (tato praxe se však používá zřídka):
two_plus_three = 2 + \
3
Moduly
Ať už se jedná o moduly vestavěné v Pythonu, nebo o moduly třetích stran, které si stáhnete, musíte je před použitím ručně importovat.
- Jednoduchý import celého modulu:
import re
my_regex = re.compile("[0-9]+", re.I)
Zde importovaný modul _re_ slouží pro regulární výrazy. Po importu modulu můžete přímo volat jeho funkce pomocí předpony s názvem modulu (re.).
- Pokud je název modulu, který importujete, již použit ve vašem kódu, můžete jej při importu namapovat na jiný název:
import re as regex
my_regex = regex.compile("[0-9]+", regex.I)
- Pokud jste “špatní”, můžete importovat celý modul do aktuálního jmenného prostoru, což může neúmyslně přepsat již definované proměnné:
match = 10
from re import * # Modul re obsahuje funkci match
print match # Vypíše funkci match
Protože jste dobří lidé, věřím, že to dělat nebudete.
Aritmetické operace
Python 2.7 standardně používá celočíselné dělení, takže $5 / 2 = 2$. Často však nechceme celočíselné dělení, a proto můžeme importovat tento modul:
from __future__ import division
Po importu bude $5 / 2 = 2.5$.
Celočíselné dělení: $5 // 2 = 2$.
Funkce
Definice funkcí
Funkce je pravidlo, které přijímá nula nebo více vstupů a vrací určitý výstup. V Pythonu definujeme funkci pomocí def jméno_funkce(parametry):
def double(x):
"""Zde můžete napsat vysvětlení funkce.
Například, tato funkce vynásobí vstup dvěma."""
# Zde může být tělo funkce, nezapomeňte na odsazení
return x * 2
Použití funkcí
V Pythonu jsou funkce “občany první třídy”, což znamená, že je můžeme přiřadit proměnné nebo je předat jako argumenty jiným funkcím:
def apply_to_one(f):
"""Volá funkci f a předává jí 1 jako argument."""
return f(1)
my_double = double # 'double' odkazuje na funkci definovanou v předchozí sekci
x = apply_to_one(my_double) # x je rovno 2
Anonymní funkce
Anonymní funkce lze také vytvářet pomocí lambda:
y = apply_to_one(lambda x: x + 4) # rovno 5
Lambda funkce lze přiřadit jiným proměnným, ale většina lidí vám doporučí, abyste se drželi def:
another_double = lambda x: 2 * x # nedoporučeno
def another_double(x): return 2 * x # doporučená praxe
Doplnění:
lambdaje pouze výraz, tělo funkce je mnohem jednodušší než udef.- Tělo
lambdaje výraz, nikoli blok kódu. Do výrazulambdalze zapouzdřit pouze omezenou logiku.
Předávání parametrů funkcí
Parametry funkce mohou mít definované výchozí hodnoty. Pokud se funkce volá bez argumentů pro tyto parametry, použijí se výchozí hodnoty; pokud jsou argumenty zadány, předají se zadané hodnoty:
def my_print(message="my default message"):
print message
my_print("hello") # Vypíše "hello"
my_print() # Vypíše "my default message"
Někdy je také velmi užitečné specifikovat argumenty přímo pomocí jejich názvů:
def subtract(a=0, b=0):
return a - b
subtract(10, 5) # vrátí 5
subtract(0, 5) # vrátí -5
subtract(b=5) # Stejné jako předchozí, vrátí -5
Řetězce
Řetězce lze vytvářet pomocí jednoduchých nebo dvojitých uvozovek (uvozovky se musí vždy shodovat):
single_quoted_string = 'data science'
double_quoted_string = "data science"
Pro speciální znaky se používá zpětné lomítko, například:
tab_string = "\t" # Reprezentuje tabulátor
len(tab_string) # rovno 1
Pokud chcete použít samotné zpětné lomítko (například pro cesty ve Windows nebo regulární výrazy), můžete ho definovat pomocí tzv. raw stringu r"":
not_tab_string = r"\t" # Reprezentuje znaky '\' a 't'
len(not_tab_string) # rovno 2
Víceřádkové řetězce se vytvářejí pomocí tří dvojitých uvozovek:
multi_line_string = """Toto je první řádek
Toto je druhý řádek
Toto je třetí řádek"""
Zpracování výjimek
Když program narazí na chybu, Python vyvolá výjimku (exception). Pokud ji nezpracujeme, program se ukončí. Výjimky lze zachytit pomocí příkazů try a except:
try:
print 0 / 0
except ZeroDivisionError:
print "Nelze dělit nulou"
Zatímco v jiných jazycích jsou výjimky často vnímány jako něco nežádoucího, v Pythonu jejich časté zpracování může vést k čistšímu a elegantnějšímu kódu.
Seznamy (Lists)
Vytváření seznamů
Seznamy jsou jednoduché uspořádané kolekce a jedna z nejzákladnějších datových struktur v Pythonu (podobné polím v jiných jazycích, ale s několika dalšími vlastnostmi). Vytvoření seznamu:
integer_list = [1, 2, 3]
heterogeneous_list = ["string", 0.1, True]
list_of_lists = [ integer_list, heterogeneous_list, [] ]
list_length = len(integer_list) # rovno 3
list_sum = sum(integer_list) # rovno 6
Přístup k prvkům seznamu
K prvkům v seznamu můžete přistupovat pomocí indexů v hranatých závorkách:
x = range(10) # vytvoří seznam x = [0, 1, ..., 9]
zero = x[0] # rovno 0, indexy seznamu začínají od 0
one = x[1] # rovno 1
nine = x[-1] # rovno 9, poslední prvek v seznamu
eight = x[-2] # rovno 8, druhý prvek od konce seznamu
x[0] = -1 # aktuální seznam x = [-1, 1, 2, 3, ..., 9]
Řezání seznamů
Pomocí hranatých závorek můžete seznamy řezat:
first_three = x[:3] # [-1, 1, 2]
three_to_end = x[3:] # [3, 4, ..., 9]
one_to_four = x[1:5] # [1, 2, 3, 4]
last_three = x[-3:] # [7, 8, 9]
without_first_and_last = x[1:-1] # [1, 2, ..., 8]
copy_of_x = x[:] # [-1, 1, 2, ..., 9]
Pomocí in můžete zkontrolovat, zda se prvek nachází v seznamu:
1 in [1, 2, 3] # True
0 in [1, 2, 3] # False
Tento způsob vyhledávání prvků je neefektivní. Měli byste ho používat pouze tehdy, když je seznam malý nebo vám nezáleží na době hledání.
Spojování seznamů
V Pythonu je velmi snadné spojit dva seznamy:
x = [1, 2, 3]
x.extend([4, 5, 6]) # Nyní x = [1,2,3,4,5,6]
Pokud nechcete upravovat původní seznam x, můžete použít operátor sčítání k vytvoření nového seznamu:
x = [1, 2, 3]
y = x + [4, 5, 6] # Nyní y = [1, 2, 3, 4, 5, 6]; x se nezměnilo
Často se používá tento způsob přidání jednoho prvku do seznamu:
x = [1, 2, 3]
x.append(0) # Nyní x = [1, 2, 3, 0]
y = x[-1] # rovno 0
z = len(x) # rovno 4
Rozbalování seznamů
Pokud víte, kolik prvků je v seznamu, je snadné jej rozbalit:
x, y = [1, 2] # Nyní x = 1, y = 2
Pokud se počet prvků na obou stranách rovnice neshoduje, dostanete chybu hodnoty (ValueError). Proto často používáme podtržítko k uložení zbytku seznamu:
_, y = [1, 2] # Nyní y == 2, první prvek je ignorován
N-tice (Tuples)
Seznamy a n-tice jsou si velmi podobné. Jediný rozdíl je v tom, že prvky v n-tici nelze měnit.
Vytváření n-tic
N-tice lze vytvářet pomocí kulatých závorek nebo bez jakýchkoli závorek:
my_tuple = (1, 2)
other_tuple = 3, 4
my_list[1] = 3 # Nyní je my_list [1, 3]
try:
my_tuple[1] = 3
except TypeError:
print "Nelze měnit n-tici"
N-tice jsou velmi užitečné pro snadné získání více návratových hodnot z funkce:
def sum_and_product(x, y):
return (x + y),(x * y)
sp = sum_and_product(2, 3) # rovno (5, 6)
s, p = sum_and_product(5, 10) # s = 15, p = 50
N-tice (a seznamy) podporují současné přiřazení více prvků:
x, y = 1, 2 # Nyní x = 1, y = 2
x, y = y, x # Výměna hodnot dvou proměnných v Pythonu; Nyní x = 2, y = 1
Slovníky (Dictionaries)
Vytváření slovníků
Další základní datovou strukturou v Pythonu je slovník, který vám umožňuje rychle získat odpovídající hodnotu (value) pomocí klíče (key):
empty_dict = {} # Velmi "pythonovská" definice prázdného slovníku
empty_dict2 = dict() # Méně "pythonovská" definice prázdného slovníku
grades = { "Joel" : 80, "Tim" : 95 } # Uložení do slovníku
Vyhledávání prvků ve slovníku
Můžete použít hranaté závorky s klíčem k vyhledání odpovídající hodnoty:
joels_grade = grades["Joel"] # rovno 80
Pokud hledaný klíč ve slovníku neexistuje, vrátí se KeyError:
try:
kates_grade = grades["Kate"]
except KeyError:
print "pro Kate není žádná známka!"
Pomocí in můžete zkontrolovat, zda klíč existuje ve slovníku:
joel_has_grade = "Joel" in grades # True
kate_has_grade = "Kate" in grades # False
Slovníky mají metodu, která vrací výchozí hodnotu, pokud hledaný klíč ve slovníku neexistuje (místo vyvolání výjimky):
joels_grade = grades.get("Joel", 0) # rovno 80
kates_grade = grades.get("Kate", 0) # rovno 0
no_ones_grade = grades.get("No One") # vrátí výchozí hodnotu None
Úprava slovníků
Pomocí hranatých závorek můžete vytvářet a upravovat páry klíč-hodnota ve slovníku:
grades["Tim"] = 99 # nahradí starou hodnotu
grades["Kate"] = 100 # přidá nový pár klíč-hodnota
num_students = len(grades) # rovno 3
Často budeme používat slovníky k vyjádření struktury dat, například takto:
tweet = {
"user" : "joelgrus",
"text" : "Data Science is Awesome",
"retweet_count" : 100,
"hashtags" : ["#data", "#science", "#datascience", "#awesome", "#yolo"]
}
Kromě vyhledávání konkrétních klíčů můžeme také pracovat se všemi klíči následujícím způsobem:
tweet_keys = tweet.keys() # Získá seznam klíčů
tweet_values = tweet.values() # Získá seznam hodnot
tweet_items = tweet.items() # Získá n-tice (klíč, hodnota)
"user" in tweet_keys # Vrátí True, používá méně efektivní hledání 'in' v seznamu
"user" in tweet # Více "pythonovské" použití, používá efektivní hledání 'in' ve slovníku
"joelgrus" in tweet_values # True
Klíče ve slovníku jsou unikátní a seznamy nemohou být použity jako klíče slovníku. Pokud potřebujete vícesložkový klíč, můžete použít n-tici nebo klíč nějakým způsobem převést na řetězec.
Vestavěné slovníky s výchozími hodnotami (defaultdict)
Pokud se snažíte spočítat frekvenci každého slova v dokumentu, zřejmým přístupem je vytvořit slovník, kde slova slouží jako klíče a jejich frekvence jako odpovídající hodnoty. Poté projdete dokumentem a pro každé slovo, které se již objevilo, zvýšíte jeho hodnotu o 1; pro slova, která se ještě neobjevila, přidáte nový pár klíč-hodnota:
word_counts = {}
for word in document:
if word in word_counts:
word_counts[word] += 1
else:
word_counts[word] = 1
Samozřejmě, můžete také předem zpracovat chybějící klíč takovýmto “nejprve udělej, pak se ptej” způsobem:
word_counts = {}
for word in document:
try:
word_counts[word] += 1
except KeyError:
word_counts[word] = 1
Třetí metodou je použití get, která se pro zpracování chybějících klíčů osvědčuje:
word_counts = {}
for word in document:
previous_count = word_counts.get(word, 0)
word_counts[word] = previous_count + 1
Vestavěné slovníky s výchozími hodnotami (defaultdict) jsou jako běžné slovníky, s jediným rozdílem: když se pokusíte vyhledat neexistující klíč, defaultdict automaticky vytvoří pár klíč-hodnota pomocí zadaného klíče. Pro použití defaultdict musíte importovat knihovnu collections:
from collections import defaultdict
word_counts = defaultdict(int) # int() generuje 0
for word in document:
word_counts[word] += 1
Vestavěné slovníky jsou velmi užitečné i se seznamy, běžnými slovníky, a dokonce i s vlastními funkcemi:
dd_list = defaultdict(list) # list() generuje prázdný seznam
dd_list[2].append(1) # Nyní je dd_list {2: [1]}
dd_dict = defaultdict(dict) # dict() generuje prázdný slovník
dd_dict["Joel"]["City"] = "Seattle" # Nyní je obsah dd_dict { "Joel" : { "City" : Seattle"}}
dd_pair = defaultdict(lambda: [0, 0]) # Vytvoří slovník, kde hodnota pro klíč je seznam
dd_pair[2][1] = 1 # Nyní je obsah dd_pair {2: [0,1]}
Tato metoda je velmi užitečná, protože v budoucnu nebudeme muset kontrolovat existenci klíče, když budeme chtít získat určité hodnoty ze slovníku.
Počítadla (Counter)
Počítadlo (Counter) dokáže přímo převést sadu hodnot na objekt podobný slovníku, kde klíčem je prvek ze sady a odpovídající hodnota je počet jeho výskytů. To se často používá při vytváření histogramů:
from collections import Counter
c = Counter([0, 1, 2, 0]) # c (přibližně) je { 0 : 2, 1 : 1, 2 : 1 }
Tímto způsobem získáme velmi pohodlný způsob, jak spočítat frekvenci slov:
word_counts = Counter(document)
Počítadlo má také velmi často používanou metodu most_common, která dokáže přímo získat několik nejčastějších slov a jejich frekvence:
# Vypíše 10 nejčastějších slov a jejich počet
for word, count in word_counts.most_common(10):
print word, count
Množiny (Sets)
Další datovou strukturou v Pythonu jsou množiny. Množina je kolekce unikátních prvků.
Množinu lze vytvořit a přidávat do ní prvky takto:
s = set()
s.add(1) # s je { 1 }
s.add(2) # s je { 1, 2 }
s.add(2) # s je { 1, 2 }
x = len(s) # rovno 2
y = 2 in s # rovno True
z = 3 in s # rovno False
Dva hlavní důvody pro použití množin:
Za prvé, operace in v množinách je velmi efektivní. Když je počet prvků v datové sadě velmi velký, je zjevně vhodnější vyhledávat prvky ve formě množiny než v seznamu:
stopwords_list = ["a","an","at"] + hundreds_of_other_words + ["yet", "you"]
"zip" in stopwords_list # Neúspěch, je třeba zkontrolovat každý prvek
stopwords_set = set(stopwords_list)
"zip" in stopwords_set # Vyhledávání úspěšné a velmi rychlé
Za druhé, použití množin je velmi pohodlné pro získání unikátních prvků ze sady dat:
item_list = [1, 2, 3, 1, 2, 3]
num_items = len(item_list) # 6
item_set = set(item_list) # {1, 2, 3}
num_distinct_items = len(item_set) # 3
distinct_item_list = list(item_set) # [1, 2, 3]
V praxi se však množiny stále nepoužívají tak často jako slovníky a seznamy.
Podmíněné příkazy
Ve většině programovacích jazyků můžete použít _if_ pro podmíněné větvení takto:
if 1 > 2:
message = "if only 1 were greater than two…"
elif 1 > 3:
message = "elif stands for 'else if'"
else:
message = "when all else fails use else (if you want to)"
Podmíněný příkaz můžete napsat i na jeden řádek, ale to se používá zřídka:
parity = "even" if x % 2 == 0 else "odd"
Cykly
Cyklus while
Cyklus while v Pythonu:
x = 0
while x < 10:
print x, "is less than 10"
x += 1
Cyklus for
Častěji se používá cyklus for-in:
for x in range(10):
print x, "is less than 10"
Složitější logické výrazy mohou používat příkazy continue a break:
for x in range(10):
if x == 3:
continue # Přeskočí na další iteraci cyklu
if x == 5:
break # Úplně opustí cyklus
print x
Výsledkem bude výstup 0, 1, 2 a 4.
Pravdivostní hodnota (Truthiness)
Booleovské proměnné Booleans v Pythonu se používají podobně jako v jiných jazycích, s jediným rozdílem, že první písmeno musí být vždy velké:
one_is_less_than_two = 1 < 2 # je True
true_equals_false = True == False # je False
Python používá None k označení absence hodnoty, podobně jako null v jiných jazycích:
x = None
print x == None # Vypíše True, není to nejelegantnější
print x is None # Vypíše True, je to elegantnější
Python umožňuje používat jiné hodnoty místo booleovských. Následující jsou ekvivalentní False:
- False
- None
- [] (prázdný seznam)
- {} (prázdný slovník)
- “”
- set()
- 0
- 0.0
Podobně existuje mnoho ekvivalentů True, což vám velmi usnadňuje kontrolu, zda jsou seznamy, řetězce, slovníky atd. prázdné.
Samozřejmě, pokud nemůžete předvídat výsledek, můžete se při používání dopustit chyb:
s = some_function_that_returns_a_string()
if s:
first_char = s[0]
else:
first_char = ""
Jednodušší přístup, který má stejný účinek jako ten výše:
first_char = s and s[0]
Pokud je první hodnota pravdivá, vrátí se druhá hodnota; jinak se vrátí první hodnota.
Podobně, pokud x může být číslo nebo None, pak takto můžete získat x, které bude určitě číslo:
safe_x = x or 0
V Pythonu existuje také funkce all, která vrátí True, pokud jsou všechny prvky True. Funkce any vrátí True, pokud je alespoň jeden prvek True. Například pro seznam, kde je každý prvek “pravdivý”, funkce all vrátí True, jinak vrátí False:
all([True, 1, { 3 }]) # True
all([True, 1, {}]) # False, {} je ekvivalentní 'False'
any([True, 1, {}]) # True
all([]) # True, neexistuje žádný prvek ekvivalentní 'False'
any([]) # False, neexistuje žádný prvek ekvivalentní 'True'
Pro pokročilé čtenáře:
Běžná syntaxe Pythonu v datové vědě (pokročilé)