Dažnai naudojama Python sintaksė duomenų moksle (pagrindai)

Pastarosiomis dienomis skaitau knygą „Data Science from Scratch“ (PDF adresas), kuri yra puikus ir lengvai suprantamas įvadas į duomenų mokslą. Viename iš skyrių pristatoma pagrindinė Python sintaksė ir pažangesnė sintaksė, dažnai naudojama duomenų moksle. Kadangi man patiko, kaip aiškiai ir glaustai tai pateikta, nusprendžiau išversti ir pasidalinti čia, kaip atmintinę.

Dažnai naudojama Python sintaksė duomenų moksle (pagrindai) Dažnai naudojama Python sintaksė duomenų moksle (pažengusiems)

Šiame skyriuje daugiausia dėmesio skiriama pagrindinei Python sintaksei ir funkcijoms, kurios yra itin naudingos duomenų apdorojimui (pagrįsta Python 2.7 versija).

Įtraukos

Nors daugelis programavimo kalbų naudoja skliaustus kodo blokams kontroliuoti, Python tam pasitelkia įtraukas (angl. indentation):

for i in [1, 2, 3, 4, 5]:  
    print i          # pirmoji "for i" ciklo eilutė  
    for j in [1, 2, 3, 4, 5]:  
        print j      # pirmoji "for j" ciklo eilutė  
        print i + j  # paskutinė "for j" ciklo eilutė  
    print i          # paskutinė "for i" ciklo eilutė  
print "done looping"  

Dėl to Python kodas yra itin lengvai skaitomas, tačiau taip pat reiškia, kad privalote nuolat atidžiai stebėti formatavimą. Skliausteliuose esantys tarpai ignoruojami, o tai labai praverčia rašant ilgas išraiškas:

long_winded_computation = (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20)  

Tai padeda kodą padaryti skaitomesniu:

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 ] ]  

Kelių eilučių sakiniai

Dviejų eilučių sujungimą, nutraukiant vieną iš jų, galima pažymėti atvirkštiniu brūkšniu (šis metodas naudojamas retai):

two_plus_three = 2 + \
                 3  

Moduliai

Tiek standartiniai Python moduliai, tiek trečiųjų šalių moduliai, kuriuos atsisiunčiate patys, turi būti rankiniu būdu importuojami, kad juos būtų galima naudoti.

  1. Tiesioginis viso modulio importavimas:
import re  
my_regex = re.compile("[0-9]+", re.I)  

Čia importuotas re modulis skirtas reguliariosioms išraiškoms. Importavus modulį, konkrečias jo funkcijas galima iškviesti naudojant modulio pavadinimą kaip priešdėlį (pvz., re.).

  1. Jei importuojamo modulio pavadinimas jau naudojamas jūsų kode, galite jam priskirti kitą pavadinimą importavimo metu:
import re as regex  
my_regex = regex.compile("[0-9]+", regex.I)  
  1. Jei norite elgtis „blogai“, galite importuoti visą modulį į dabartinę vardų erdvę. Taip galite netyčia perrašyti jau apibrėžtus kintamuosius:
match = 10  
from re import *  # re modulyje yra funkcija match  
print match       # išveda match funkciją  

Kadangi esate geras žmogus, tikiu, kad to nedarysite.

Aritmetinės operacijos

Python 2.7 pagal nutylėjimą naudoja sveikųjų skaičių dalybą, todėl $5 / 2 = 2$. Tačiau dažnai mums reikia ne sveikųjų skaičių dalybos, todėl galima importuoti šį modulį:

from __future__ import division  

Importavus, $5 / 2 = 2.5$. Sveikųjų skaičių dalyba: $5 // 2 = 2$.

Funkcijos

Funkcijos apibrėžimas

Funkcija yra taisyklė, kuri gali priimti nulį ar daugiau įvesties duomenų ir grąžinti tam tikrą išvestį. Python kalboje funkcijas apibrėžiame naudodami def funkcijos_pavadinimas(parametrai):

def double(x):  
    """Čia galite parašyti paaiškinimą apie funkcijos veikimą.  
    Pavyzdžiui, ši funkcija padvigubina įvestį."""  
    # Čia rašomas funkcijos kūnas, nepamirškite įtraukų.  
    return x * 2  

Funkcijų naudojimas

Python kalboje funkcijos yra „pirmos klasės piliečiai“, o tai reiškia, kad jas galima priskirti kintamiesiems arba perduoti kaip argumentus kitoms funkcijoms:

def apply_to_one(f):  
    """Iškviesti funkciją f ir perduoti jai 1 kaip parametrą"""  
    return f(1)  
my_double = double          # double rodo į anksčiau apibrėžtą funkciją  
x = apply_to_one(my_double) # x yra lygus 2  

Anoniminės funkcijos

Taip pat galima kurti anonimines funkcijas naudojant lambda:

y = apply_to_one(lambda x: x + 4)     # yra lygu 5  

lambda išraišką galima priskirti kintamiesiems, tačiau dauguma rekomenduotų vis tiek naudoti def:

another_double = lambda x: 2 * x      # nerekomenduojama  
def another_double(x): return 2 * x   # rekomenduojama  

Pastabos:

Funkcijų parametrų perdavimas

Funkcijos parametrams galima nustatyti numatytąsias vertes. Jei funkcija iškviečiama be parametrų, bus naudojamos numatytosios vertės; jei su parametrais, bus perduotos nurodytos vertės:

def my_print(message="my default message"):  
    print message  
my_print("hello")     # išveda "hello"  
my_print()            # išveda "my default message"  

Kartais labai patogu nurodyti parametrus tiesiogiai pagal jų pavadinimus:

def subtract(a=0, b=0):  
    return a - b  
subtract(10, 5)   # grąžina 5  
subtract(0, 5)    # grąžina -5  
subtract(b=5)     # tas pats, kas ankstesnis, grąžina -5  

Eilutės

Norėdami sukurti eilutę, galite naudoti viengubas arba dvigubas kabutes (kabutės turi būti suporuotos):

single_quoted_string = 'data science'  
double_quoted_string = "data science"  

Atvirkštinis brūkšnys naudojamas išskyrimo simboliams, pavyzdžiui:

tab_string = "\t"      # žymi tabuliavimo simbolį (tab)  
len(tab_string)        # lygu 1  

Kai norite naudoti patį atvirkštinį brūkšnį (pvz., Windows kataloguose arba reguliariosiose išraiškose), galite tai apibrėžti naudodami „žaliąsias“ eilutes r"":

not_tab_string = r"\t" # žymi simbolius '\' ir 't'  
len(not_tab_string)    # lygu 2  

Daugiatikslės eilutės kuriamos naudojant tris dvigubas kabutes:

multi_line_string = """Tai pirma eilutė  
Tai antra eilutė  
Tai trečia eilutė"""  

Išimčių valdymas

Kai programoje įvyksta klaida, Python generuoja išimtį. Jei jos neapdorosime, programa sustos. Išimtis galima valdyti naudojant try ir except teiginius:

try:  
    print 0 / 0  
except ZeroDivisionError:  
    print "Negalima dalinti iš nulio"  

Nors kitose kalbose išimtys dažnai laikomos neigiamu dalyku, Python kalboje aktyvus išimčių valdymas gali padaryti jūsų kodą švaresnį ir elegantiškesnį.

Sąrašai

Sąrašų kūrimas

Sąrašai yra paprastos, tvarkingos kolekcijos ir yra pagrindinė Python duomenų struktūra (panašios į kitų kalbų masyvus, bet turi papildomų savybių). Štai kaip sukurti sąrašą:

integer_list = [1, 2, 3]  
heterogeneous_list = ["string", 0.1, True]  
list_of_lists = [ integer_list, heterogeneous_list, [] ]  
list_length = len(integer_list)   # lygu 3  
list_sum = sum(integer_list)      # lygu 6  

Sąrašo elementų pasiekimas

Sąrašo elementus galite pasiekti naudodami kvadratinius skliaustus ir indeksus:

x = range(10)       # sąrašas x = [0, 1, ..., 9]  
zero = x[0]         # lygu 0, sąrašo indeksavimas prasideda nuo 0  
one = x[1]          # lygu 1  
nine = x[-1]        # lygu 9, paskutinis sąrašo elementas  
eight = x[-2]       # lygu 8, antras nuo galo sąrašo elementas  
x[0] = -1           # dabar sąrašas x = [-1, 1, 2, 3, ..., 9]  

Sąrašo išpjovimas (slicing)

Sąrašus galima išpjauti naudojant kvadratinius skliaustus:

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]  

Galite naudoti in operatorių, norėdami patikrinti, ar elementas yra sąraše:

1 in [1, 2, 3]        # True  
0 in [1, 2, 3]        # False  

Šis elementų paieškos būdas yra neefektyvus. Naudokite jį tik tada, kai sąrašas yra labai mažas arba kai jums nerūpi paieškos laikas.

Sąrašų jungimas

Python kalboje labai lengva sujungti du sąrašus:

x = [1, 2, 3]  
x.extend([4, 5, 6])   # dabar x = [1,2,3,4,5,6]  

Jei nenorite keisti originalaus sąrašo x, galite sukurti naują sąrašą naudodami „pliuso“ operatorių:

x = [1, 2, 3]  
y = x + [4, 5, 6]     # dabar y = [1, 2, 3, 4, 5, 6]; x nepakito  

Dažnai taip pridedamas vienas elementas į sąrašą:

x = [1, 2, 3]  
x.append(0)           # dabar x = [1, 2, 3, 0]  
y = x[-1]             # lygu 0  
z = len(x)            # lygu 4  

Sąrašo išpakavimas

Jei žinote, kiek elementų yra sąraše, jį lengva išpakuoti:

x, y = [1, 2]         # dabar x = 1, y = 2  

Jei elementų skaičius abiejose lygybės pusėse nesutampa, gausite ValueError. Todėl dažniau naudojame pabraukimo simbolį, kad priskirtume likusią sąrašo dalį:

_, y = [1, 2]         # dabar y == 2, pirmasis elementas ignoruojamas  

Kortelės (Tuples)

Sąrašai ir kortelės yra labai panašios, vienintelis skirtumas tas, kad kortelių elementai negali būti keičiami.

Kortelių kūrimas

Korteles galima sukurti naudojant apvalius skliaustus arba be jokių skliaustų:

my_tuple = (1, 2)  
other_tuple = 3, 4  
my_list[1] = 3        # dabar my_list yra [1, 3]  
try:  
    my_tuple[1] = 3  
except TypeError:  
    print "Kortelės negalima modifikuoti"  

Kortelės labai patogios, kai reikia grąžinti kelias reikšmes iš funkcijos:

def sum_and_product(x, y):  
    return (x + y),(x * y)  
sp = sum_and_product(2, 3)    # lygu (5, 6)  
s, p = sum_and_product(5, 10) # s = 15, p = 50  

Kortelės (ir sąrašai) palaiko kelių elementų priskyrimą vienu metu:

x, y = 1, 2       # dabar x = 1, y = 2  
x, y = y, x       # Dviejų kintamųjų reikšmių sukeitimas Python; dabar x = 2, y = 1  

Žodynai

Žodynų kūrimas

Kita pagrindinė Python duomenų struktūra yra žodynas, leidžiantis greitai gauti reikšmes (value) naudojant raktus (key):

empty_dict = {}                       # Labai "pythoniškas" tuščio žodyno apibrėžimas  
empty_dict2 = dict()                  # Mažiau "pythoniškas" tuščio žodyno apibrėžimas  
grades = { "Joel" : 80, "Tim" : 95 }  # Žodyno saugojimas  

Žodyno elementų paieška

Galite naudoti kvadratinius skliaustus ir raktą, norėdami rasti atitinkamą reikšmę:

joels_grade = grades["Joel"]          # lygu 80  

Jei ieškomas raktas nėra žodyne, bus grąžinta KeyError išimtis:

try:  
    kates_grade = grades["Kate"]  
except KeyError:  
    print "Katei pažymio nėra!"  

Galite naudoti in operatorių, norėdami patikrinti, ar raktas yra žodyne:

joel_has_grade = "Joel" in grades     # True  
kate_has_grade = "Kate" in grades     # False  

Žodynai turi metodą, kuris grąžina numatytąją reikšmę, jei ieškomas raktas nerandamas (užuot sukėlęs išimtį):

joels_grade = grades.get("Joel", 0)   # lygu 80  
kates_grade = grades.get("Kate", 0)   # lygu 0  
no_ones_grade = grades.get("No One")  # grąžina numatytąją reikšmę None  

Žodyno modifikavimas

Naudojant kvadratinius skliaustus, galima kurti ir modifikuoti žodyno rakto-reikšmės poras:

grades["Tim"] = 99                    # pakeičia seną reikšmę  
grades["Kate"] = 100                  # prideda rakto-reikšmės porą  
num_students = len(grades)            # lygu 3  

Dažnai naudosime žodynus duomenų struktūrai išreikšti, pavyzdžiui, taip:

tweet = {  
    "user" : "joelgrus",  
    "text" : "Data Science is Awesome",  
    "retweet_count" : 100,  
    "hashtags" : ["#data", "#science", "#datascience", "#awesome", "#yolo"]  
}  

Be konkrečių raktų paieškos, galime atlikti operacijas su visais raktais taip:

tweet_keys = tweet.keys()             # gaunamas raktų sąrašas  
tweet_values = tweet.values()         # gaunamas reikšmių sąrašas  
tweet_items = tweet.items()           # gaunamos (raktas, reikšmė) kortelės  
"user" in tweet_keys                  # grąžina True, naudojama mažiau efektyvi sąrašo paieška su in  
"user" in tweet                       # labiau "pythoniškas" būdas, naudojama efektyvi žodyno paieška su in  
"joelgrus" in tweet_values            # True  

Žodynų raktai turi būti unikalūs, o sąrašai negali būti naudojami kaip žodyno raktai. Jei jums reikia sudėtinio rakto, galite naudoti kortelę arba konvertuoti raktą į eilutę.

Numatytasis žodynas (defaultdict)

Jei bandote suskaičiuoti kiekvieno žodžio pasikartojimo dažnumą dokumente, akivaizdus būdas yra sukurti žodyną, kur žodis būtų raktas, o dažnumas – atitinkama reikšmė. Tada pereinate per dokumentą: kai susiduriate su jau matytu žodžiu, padidinate jo reikšmę 1; kai susiduriate su nauju žodžiu, pridedate naują rakto-reikšmės porą į žodyną:

word_counts = {}  
for word in document:  
    if word in word_counts:  
        word_counts[word] += 1  
    else:  
        word_counts[word] = 1  

Žinoma, galite iš anksto apdoroti trūkstamą raktą, naudodami „pirmiausia veiksmas, po to klausimas“ metodą, pavyzdžiui, taip:

word_counts = {}  
for word in document:  
    try:  
        word_counts[word] += 1  
    except KeyError:  
        word_counts[word] = 1  

Trečias metodas yra naudoti get metodą, kuris puikiai tinka trūkstamiems raktams tvarkyti:

word_counts = {}  
for word in document:  
    previous_count = word_counts.get(word, 0)  
    word_counts[word] = previous_count + 1  

Numatytieji žodynai (defaultdict) veikia kaip įprasti žodynai, vienintelis skirtumas yra tas, kad bandant rasti neegzistuojantį raktą, defaultdict automatiškai sukurs rakto-reikšmės porą, naudodamas jūsų pateiktą raktą. Norėdami naudoti defaultdict, turite importuoti collections biblioteką:

from collections import defaultdict  
word_counts = defaultdict(int)        # int() sukuria 0  
for word in document:  
    word_counts[word] += 1  

Numatytieji žodynai taip pat labai naudingi su sąrašais, paprastais žodynais ir net su vartotojo apibrėžtomis funkcijomis:

dd_list = defaultdict(list)           # list() sukuria tuščią sąrašą  
dd_list[2].append(1)                  # dabar dd_list yra {2: [1]}  
dd_dict = defaultdict(dict)           # dict() sukuria tuščią žodyną  
dd_dict["Joel"]["City"] = "Seattle"   # dabar dd_dict turinys yra { "Joel" : { "City" : "Seattle"}}  
dd_pair = defaultdict(lambda: [0, 0]) # sukūrė žodyną, kurio rakto reikšmė yra sąrašas  
dd_pair[2][1] = 1                     # dabar dd_pair turinys yra {2: [0,1]}  

Šis metodas yra labai naudingas, nes ateityje, kai reikės gauti tam tikras rakto-reikšmės poras iš žodyno, nebereikės tikrinti, ar raktas egzistuoja.

Skaitiklis (Counter)

Skaitiklis (Counter) gali tiesiogiai paversti verčių grupę į žodyną primenantį objektą, kur raktas yra elementas iš grupės, o atitinkama reikšmė – to elemento pasikartojimų skaičius. Tai dažnai naudojama kuriant histogramas:

from collections import Counter  
c = Counter([0, 1, 2, 0]) # c (apytiksliai) yra { 0 : 2, 1 : 1, 2 : 1 }  

Taigi, turime labai patogų būdą skaičiuoti žodžių dažnumą:

word_counts = Counter(document)  

Skaitiklis turi dar vieną labai naudingą metodą most_common, kuris leidžia tiesiogiai gauti kelis dažniausius žodžius ir jų dažnumą:

# Išveda 10 dažniausių žodžių ir jų skaičių  
for word, count in word_counts.most_common(10):  
    print word, count  

Aibės

Kita Python duomenų struktūra yra aibė. Aibė yra skirtingų elementų rinkinys. Aibę galima sukurti ir į ją pridėti elementų taip:

s = set()  
s.add(1)          # s yra { 1 }  
s.add(2)          # s yra { 1, 2 }  
s.add(2)          # s yra { 1, 2 }  
x = len(s)        # lygu 2  
y = 2 in s        # lygu True  
z = 3 in s        # lygu False  

Dvi pagrindinės priežastys naudoti aibes:

Pirma, in operacija aibėse yra labai efektyvi. Kai duomenų rinkinyje yra labai daug elementų, elementų paieška aibės pavidalu akivaizdžiai tinka labiau nei sąrašo atveju:

stopwords_list = ["a","an","at"] + hundreds_of_other_words + ["yet", "you"]  
"zip" in stopwords_list               # Nepavyksta, reikia tikrinti kiekvieną elementą  
stopwords_set = set(stopwords_list)  
"zip" in stopwords_set                # Paieška sėkminga ir labai greita  

Antra, aibės labai patogios, norint gauti unikalius elementus iš duomenų rinkinio:

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]  

Tačiau praktiškai aibės naudojamos rečiau nei žodynai ir sąrašai.

Sąlyginiai teiginiai

Daugumoje programavimo kalbų sąlygines šakas galite išreikšti naudodami if teiginį taip:

if 1 > 2:  
    message = "jei tik 1 būtų didesnis už 2…"  
elif 1 > 3:  
    message = "elif reiškia 'else if' (kitaip jei)"  
else:  
    message = "kai viskas nepavyksta, naudokite else (jei norite)"  

Sąlyginės šakos teiginį taip pat galite parašyti vienoje eilutėje, tačiau tai naudojama retai:

parity = "even" if x % 2 == 0 else "odd"  

Ciklo teiginiai

while ciklas

while ciklas Python kalboje:

x = 0  
while x < 10:  
    print x, "yra mažiau nei 10"  
    x += 1  

for ciklas

Dažniau naudojamas for-in ciklas:

for x in range(10):  
    print x, "yra mažiau nei 10"  

Sudėtingesnėms loginėms išraiškoms galima naudoti continue ir break teiginius:

for x in range(10):  
    if x == 3:  
        continue          # iškart pereina į kitą ciklo iteraciją  
    if x == 5:  
        break             # visiškai išeina iš ciklo  
    print x  

Rezultatas bus 0, 1, 2 ir 4.

Teisingumo reikšmė (Truthiness)

Python kalbos Būlio kintamieji Booleans naudojami panašiai kaip ir kitose kalbose, vienintelis skirtumas yra tas, kad pirmoji raidė visada turi būti didžioji:

one_is_less_than_two = 1 < 2      # yra True  
true_equals_false = True == False # yra False  

Python naudoja None, norėdama nurodyti, kad reikšmė neegzistuoja, panašiai kaip kitose kalbose null:

x = None  
print x == None        # išveda True, bet tai nėra elegantiška  
print x is None        # išveda True, tai elegantiškiau  

Python leidžia naudoti kitas reikšmes vietoj Būlio reikšmių. Šios reikšmės yra lygiavertės False:

Panašiai yra daug True ekvivalentų, o tai leidžia labai patogiai patikrinti, ar sąrašas, eilutė ar žodynas yra tuščias ir t.t.

Žinoma, jei negalite numatyti rezultato, naudodami tai galite suklysti:

s = some_function_that_returns_a_string()  
if s:  
    first_char = s[0]  
else:  
    first_char = ""  

Paprastesnis būdas, kurio poveikis yra toks pat kaip ir aukščiau pateikto:

first_char = s and s[0]  

Jei pirmoji reikšmė yra teisinga, grąžinama antroji reikšmė; priešingu atveju grąžinama pirmoji reikšmė.

Panašiai, jei x gali būti skaičius arba None, taip galite gauti x, kuris tikrai bus skaičius:

safe_x = x or 0  

Python taip pat turi funkciją all, kuri grąžina True, jei kiekvienas elementas yra True. Funkcija any grąžina True, jei bent vienas elementas yra True. Pavyzdžiui, jei sąrašo kiekvienas elementas yra „teisingas“, all funkcija grąžins True, priešingu atveju – False:

all([True, 1, { 3 }])       # True  
all([True, 1, {}])          # False, {} yra lygiavertė „False“  
any([True, 1, {}])          # True  
all([])                     # True, nėra nei vieno elemento lygiaverčio „False“  
any([])                     # False, nėra nei vieno elemento lygiaverčio „True“  

Tolesnis skaitymas: Dažnai naudojama Python sintaksė duomenų moksle (pažengusiems)