ilustracja do wpisu o AI przedstawiająca barmana wygenerowanego w https://playgroundai.com/
intel

Gdzie jest sztuczna inteligencja, czyli jak rozgryźć barmana uczeniem maszynowym

Sztuczna inteligencja otacza nas z kolejnych stron i wypełnia kolejne obszary naszego życia. Ale czy kiedykolwiek zastanawiałeś się, jak to tak naprawdę działa? W dzisiejszym wpisie chcę Cię wprowadzić do tego świata i pokazać Ci prosty przykład AI – drzewo decyzyjne. Chcę, żebyś po przeczytaniu tego wpisu zobaczył, że to mistyczne uczenie maszynowe wcale nie jest takie trudne (przynajmniej jeśli chodzi o podstawy) i że nie musimy się obawiać buntu maszyn. A jednocześnie poznał odrobinę podstaw języka Python.


Żeby nie przynudzać teorią, tylko do razu przejść do praktyki: grafikę do tego wpisu wygenerowałem w PlaygroundAI, a w pisaniu wstępu pomógł mi ChatGPT.

Czego się nauczę?

W tym wpisie chcę Ci pokazać, jak samemu nauczyć (w języku Python) bardzo prosty model sztucznej inteligencji (artificial intelligence – AI). Będą to totalne podstawy, więc nie musisz wiedzieć w tym momencie wiedzieć na ten temat absolutnie nic. Zaczniemy od zera.

Jak czytać ten wpis?

Jeśli dopiero zaczynasz przygodę z kodowaniem i chcesz naprawdę zrozumieć, o czym piszę, przejdź przez cały wpis i uruchom u siebie kod, który podaję. Najlepiej, jeśli potem trochę się nim pobawisz i spróbujesz go poprawić, zepsuć albo po prostu zmienić żebyś wiedział, jakie efekty dadzą Twoje modyfikacje.

Jeśli chcesz tylko zrozumieć, jak działa sztuczna inteligencja, ale nie jesteś zainteresowany nauką Pythona, możesz przeczytać tekst pomijając fragmenty kodu. Nie obrażę się.

Jeśli już siedzisz w temacie AI i ML, prawdopodobnie nie będę potrafił Cię za wiele nauczyć. Za to będę wdzięczny, jeśli przeglądniesz ten wpis i skomentujesz, jeśli gdzieś popełniłem błąd albo napisałem coś niedokładnie.

Niezależnie od Twojego stopnia zaawansowania – pod wpisem znajdziesz miejsce na komentarze, w którym możesz zadać mi dowolne pytanie.

Lubię się dzielić wiedzą, dlatego możesz czytać ten (i inne) wpisy bez ograniczeń. Jeśli jednak chciałbyś, możesz mi postawić kawę za to, czego się nauczysz:

Postaw mi kawę na buycoffee.to

Jak uruchomić kody z tego wpisu?

We wpisie znajdziesz fragmenty kodu napisane w Pythonie. Jeżeli nie masz zainstalowanego interpretera tego języka na komputerze, najłatwiej będzie Ci uruchomić je przez Google Colab (do działania wymaga konta Google).

Jeśli to Twoje pierwsze spotkanie z Pythonem i chcesz się go nauczyć, gorąco polecam przepisywanie kodu przed uruchomieniem. Dzięki temu lepiej poznasz składnię języka i używane funkcje. Jeśli znasz już podstawy, możesz po prostu przeczytać i skopiować fragmenty kodu.

Wykorzystując Google Colab, każdą komórkę uruchomisz naciskając ctrl+Enter.

Jeśli po skopiowaniu kodu masz problem z jego uruchomieniem sprawdź, czy nie wynika on z interpretacji wcięć (mogę mieć tabulację skonfigurowaną inaczej, niż Ty). Jeśli nie to jest przyczyną i nadal masz problemy, daj znać. Przed opublikowaniem uruchomiłem cały kod, ale zawsze mogłem czegoś nie przewidzieć.

Po przygotowaniu mojego przykładu zorientowałem się, że niektóre elementy kodu (jak komentarze, nazwy funkcji i zmiennych) napisałem po angielsku, a inne (jak wartości zmiennych) po polsku. To już z przyzwyczajenia – mam nadzieję, że nie przeszkodzi Ci to w zrozumieniu kodu.

Jak zrozumieć uczenie maszynowe?

Trochę sensacji, czyli tworzymy kontekst

Żeby było ciekawiej, całą historię osadzimy w historii sensacyjnej. Wyobraź sobie, że obudziłeś się na plaży, wyrzucony przez morze – jak Leonardo DiCaprio na początku „Incepcji” (nie lubię tego filmu, ale akurat mi się skojarzył) – i nie za bardzo wiesz, gdzie się znalazłeś. Rozglądasz się i widzisz przy plaży bar, do którego postanawiasz się udać.

Tutaj następuje prawdziwie hollywoodzkie naciąganie, bo podczas przejścia kilkudziesięciu metrów, słońce zdąży wysuszyć Twoje ubranie, a Ty jakoś doprowadzasz się do stanu używalności publicznej, więc nie wzbudzasz większej sensacji. Jak James Bond otwierasz drzwi i widzisz klasyczny lokal, jakich wiele w filmach o bohaterach samotnie przybywających w obce miejsce. W słabo oświetlonej sali siedzą klienci, z których większość wygląda na stałych bywalców tego miejsca. Mierzą Cię znudzonymi oczami, ale nie wzbudzasz większego zainteresowania i szybko wracają do przerwanych rozmów. Siadasz przy barze, gdzie barman wyciera szklankę brudną szmatą, obserwując co się dzieje w jego perymetrze.

Oczywiście, chętnie byś się czegoś napił. Ale że nie wiesz, gdzie jesteś, nie wiesz też, co możesz zamówić. Najprostsze rozwiązanie zasugerowałoby zapytanie barmana, gdzie trafiłeś, ale to całkowicie popsułoby nam fabułę, dlatego decydujesz się podejść do tematu inaczej: posiedzisz i poobserwujesz, co zamawiają inni, a może to nasunie Ci, gdzie jesteś.

Wpis nie ma na celu promowania napojów alkoholowych ani przesiadywania w knajpie. Po prostu chciałem znaleźć jakiś przykład decyzji opartej o kilka czynników, której nie widziałem jeszcze we wpisach o sztucznej inteligencji. Jeśli nie masz 18 lat – nie sięgaj po alkohol. Jeśli jesteś pełnoletni – pij odpowiedzialnie i nawet nie myśl o tym, żeby potem prowadzić jakiś pojazd mechaniczny.

Obserwacja

Posiedziałeś chwilę i udało Ci się podsłuchać rozmowy barmana z 10 klientami. Każdą osobę zapytał o dwie rzeczy:

  • Ile masz lat?
  • Jak dostałaś/eś się do baru?

i na tej podstawie niektórzy dostali do wypicia coś mocniejszego, a inni – nie. Zanotowałeś to na kartce i masz teraz przed sobą następującą tabelę:

wiektransportdecyzja
42rowernie sprzedawaj
21pieszosprzedaj
17komunikacja miejskanie sprzedawaj
18pieszonie sprzedawaj
82samochódnie sprzedawaj
63samochódnie sprzedawaj
37taxisprzedaj
64pieszosprzedaj
67rowernie sprzedawaj
20komunikacja miejskasprzedaj

Przeanalizuj ją teraz i spróbuj zgadnąć, jakimi zasadami kieruje się barman w czasie sprzedaży alkoholu.

Żeby sprawdzić, czy masz rację, postanowiłeś posiedzieć jeszcze chwilę i zobaczyć, czy dobrze przewidzisz decyzję barmana w przypadku kolejnych 10 gości. Przy przykładach poniżej zapisz, kto według Ciebie będzie może liczyć na drinka.

wiektransport
58rower
20pieszo
69komunikacja miejska
77samochód
34pieszo
18pieszo
24pieszo
19taxi
26pieszo
18taxi

Gdy masz już swoje typy możemy sprawdzić, jak z tym zadaniem poradzi sobie sztuczna inteligencja.

Przygotowanie danych

Przede wszystkim, musisz zdigitalizować swoje notatki. Oczywiście, Twój przenośny skaner zepsuł się od słonej wody, więc musisz wszystko wprowadzić „z palca”. Później powiem Ci, jak tak naprawdę otrzymałem te dane:-).

Żeby ułatwić sobie pracę, zaczniemy od zaimportowania dwóch modułów często używanych w analizie danych i uczeniu maszynowym: PandasNumPy. Posłuży nam do tego polecenie import.

Następnie utworzymy obiekt DataFrame, który po polsku byśmy nazwali ramką danych, ale dla nas będzie po prostu tabelą. W poniższym kodzie zapis pd.DataFrame oznacza, że polecenia DataFrame (tworzącego ramkę danych) interpreter Pythona ma szukać w pakiecie Pandas, który w czasie importowania skrótowo nazwaliśmy pd. Dla naszej tabeli zdefiniujemy trzy kolumny (formalnie będą to serie danych – obiekty typu pd.Series): wiek, transportdecyzja (bo takie dane zebrałeś podsłuchując barmana) i w każdej z nich kolejne obserwacje zapiszemy jako listy (obecne w „czystym” Pythonie obiekty list). Całą ramkę danych przypiszemy (operatorem =) do zmiennej o nazwie orders, którą na sam koniec wyświetlisz wywołując jej nazwę. Jak wspomniałem, cały kod możesz wykonać naciskając w Google Colab równocześnie ctrl+Enter.

import pandas as pd
import numpy as np

orders = pd.DataFrame({
    'wiek': [42, 21, 17, 18, 82, 63, 37, 64, 67, 20],
    'transport': ['rower', 'pieszo', 'komunikacja miejska', 'pieszo', 'samochód', 'samochód', 'taxi', 'pieszo', 'rower', 'komunikacja miejska'],
    'decyzja': ['nie sprzedawaj', 'sprzedaj', 'nie sprzedawaj', 'nie sprzedawaj', 'nie sprzedawaj', 'nie sprzedawaj', 'sprzedaj', 'sprzedaj', 'nie sprzedawaj', 'sprzedaj']
})

orders

Teraz, żeby Twoje notatki były łatwiejsze do odczytania z punktu widzenia algorytmu, odrobinę je przerobimy. Kolumnę z decyzją barmana, która jest naszą zmienną celu, zmienię z opisowej na liczbową. Teraz 1 będzie oznaczało, że ta osoba mogła kupić alkohol, a 0 – że nie. Wykorzystamy do tego metodę map, którą zastosujemy na wybranej serii danych (jak widzisz, możesz wywołać konkretną serię z ramki danych przywołując jej nazwę w nawiasach kwadratowych)

orders['decyzja'] = orders['decyzja'].map({'sprzedaj': 1, 'nie sprzedawaj': 0})

Bardzo podobnej komendy użyjemy potem, żeby z powrotem uzyskać informację w formie opisu.

Chcę też przetworzyć kolumnę z nazwą środka transportu. Tutaj jednak pojawia się pewien problem: jak to zrobić dobrze? Dane, w których mamy jedną z kilku możliwych opcji nazywamy kategorycznymi. Mógłbym teraz przypisać każdej z naszej kategorii wartość liczbową – na przykład według klucza:

samochód0
rower1
pieszo2
komunikacja miejska3
taxi5

Człowiek nie będzie miał problemu z połapaniem się w takim zapisie, o ile tylko orientuje się w różnych metodach przemieszczania się po mieście. Jednak ktoś, kto by nie wiedział do końca, czym się różni taksówka od roweru, mógłby się zacząć zastanawiać jaki jest sens w tym, że jeden środek transportu ma przypisaną wartość wyższą od innego. Czasami takie uszeregowanie wartości miałoby sens – na przykład jeśli chcielibyśmy pokazać, że jeden środek transportu jest szybszy albo tańszy od innego. W naszym przypadku tak nie jest i nie chcę, żeby komputer tak kombinował. Dlatego rozdzielę kolumnę transport na kilka osobnych, odpowiadających poszczególnym środkom transportu. W kolumnie odpowiadającej temu, jak konkretny klient trafił do baru, pojawi się wartość 1, a w pozostałych – 0. Na przykład wiersz:

indexwiekśrodek transportudecyzja
121pieszo1

będzie teraz wyglądał tak:

indexwieksamochódrowerpieszokomunikacja miejskatexidecyzja
121001001

Żeby przekształcić dane do takiej formy, wykorzystam metodę get_dummies i dołączę (za pomocą metody concat) jej wynik do naszej ramki danych z zamówieniami. Dla eleganckiego rozwiązania, usunę potem oryginalną kolumnę transport i zmienię kolejność kolumn tak, żeby decyzja barmana pozostała na końcu – jak w przykładzie powyżej.

orders = pd.concat([orders, pd.get_dummies(orders.transport)], axis=1)
orders.drop('transport', axis =1, inplace = True)
orders = orders[['wiek', 'komunikacja miejska', 'pieszo', 'rower', 'samochód', 'taxi', 'decyzja']]
orders

Powinieneś teraz zobaczyć następującą tabelę z danymi:


index
wiekkomunikacja miejskapieszorowersamochódtaxidecyzja
042001000
121010001
217100000
318010000
482000100
563000100
637000011
764010001
867001000
920100001

Nauka algorytmu

Teraz, gdy mamy już przygotowane dane, dochodzimy do punktu kulminacyjnego: spróbujemy nauczyć czegoś algorytm sztucznej inteligencji.

No dobra, zanim to zrobimy, musimy jakiś algorytm wybrać. Nie będę go pisał od zera – skorzystamy z tego, co już ktoś zaimplementował w pakiecie scikit-learn (z nadzieją, że autor zrobił to dobrze:-)). Bez większego opisywania, wybiorę dla przykładu algorytm oparty na drzewie decyzyjnym (decission tree). Jak taki algorytm działa – możesz poczytać na przykład na Wikipedii albo w dokumentacji pakietu, którego użyjemy. Możesz też dać mi znać w komentarzu, jeśli powinienem o tym napisać oddzielny wpis.

Zanim wykorzystamy Twoje notatki do nauczenia sztucznej inteligencji, zrobimy jeszcze jedną rzecz: rozdzielimy naszą tabelę na dwie ramki danych. Jedna będzie zawierała parametry klienta (czyli wszystkie dane wejściowe dla modelu), a druga – decyzję barmana (czyli zmienną celu). Nie musimy tego robić, ale w ten sposób trenowanie algorytmu będzie bardziej czytelne.

train_x = orders[['wiek', 'komunikacja miejska', 'pieszo', 'samochód', 'taxi', 'rower']]
train_y = orders['decyzja']

Po wybraniu algorytmu, podzielę nasz zbiór danych (losowo, ale będzie to losowanie kontrolowane, żebyś mógł je powtórzyć z takim samym wynikiem – posłuży mi do tego parametr random_state, który ustawię na 0, a więcej o nim przeczytasz we wpisie o liczbach pseudolosowych) na część uczącą i sprawdzającą w stosunku 8:2. Na ośmiu obserwacjach uczących algorytm spróbuje rozpoznać zasady wyznaczania naszej zmiennej celu (czyli podjęcia decyzji o sprzedaży alkoholu). Następnie dla dwóch obserwacji testowych spróbuje wyznaczyć zmienną celu i porówna wynik z wartościami, które usłyszeliśmy od barmana. W pewnym momencie algorytm uzna, że wystarczająco dobrze odtwarza odpowiedzi w zbiorze testowym i powie nam, że już się nauczył.

from sklearn.tree import DecisionTreeClassifier

dtc = DecisionTreeClassifier(random_state = 0)
dtc.fit(train_x, train_y)

Jeśli odpaliłeś ten kod – gratuluję! Właśnie nauczyłeś algorytm uczenia maszynowego zasad sprzedaży naszego etycznego barmana!

Nawet jeśli wydaje Ci się to bardzo proste, to dałeś komputerowi kilka obserwacji, a on patrząc na nie zaczął – lepiej lub gorzej, ale zawsze – podejmować takie same decyzje dla kolejnych przypadków. Na tym właśnie polega sztuczna inteligencja.

Skoro mamy już wyuczony algorytm, sprawdźmy go w boju – zobaczmy, czy jesteśmy w stanie przewidzieć, jaką odpowiedź usłyszeli od barmana kolejni klienci. Będziesz mógł porównać wynik działania naszego algorytmu z Twoimi przewidywaniami.

Wyjaśnienie małej ściemy – czyli ujęcie klasyczne

Za chwilę zaczniemy testować nasz algorytm. Ale zanim to zrobimy, przyznam Ci się do jednej rzeczy, żeby dalsza zabawa kodem poszła nam sprawniej: znam zasady, którymi kieruje się barman.

Chociaż trochę wcześniej kazałem Ci przepisać (albo skopiować) ramkę danych z informacjami o zamówieniach, tak naprawdę wcale nie spędziłem szczególnie dużo czasu na wymyślaniu tych kombinacji wieku i środka transportu. Wygenerowałem je poniższym kodem:

transport_no = ['samochód', 'rower']
other_transport = ['pieszo', 'komunikacja miejska', 'taxi']

np.random.seed(12) # seed zapewnia dwóch nieletnich w grupie pierwszych 10 klientów
orders = pd.DataFrame(np.random.randint(15,85,size = 10), columns = ['wiek'])
orders['transport'] = np.random.choice(transport_no+other_transport, size = len(orders))
orders

W pierwszych linijkach zdefiniowałem dwie listy: transport_no, zawierającą środki transportu, które wykluczają spożycie alkoholu, i other_transport, ze sposobami dotarcia do baru, które pozwalają na drinka. Jeśli chcesz pobawić się tym kodem, możesz śmiało dodać więcej opcji – pamiętaj tylko, że w Pythonie wartości tekstowe (zmienne typu string) trzeba umieścić w cudzysłowie ("") lub pomiędzy apostrofami ('').

Samą ramkę z zestawem klientów wygenerowałem przez losowanie za pomocą biblioteki numpy.random – a właściwie pseudolosowanie przy zdefiniowanym ziarnie o wartości 70 (znowu: jeśli nie wiesz, o co chodzi z ziarnem, zerknij do mojego wpisu o komputerowym losowaniu). Najpierw wygenerowałem kolumnę wiek, zawierającą 10 liczb całkowitych pomiędzy 15 a 85, a następnie dodałem do tego drugą kolumnę, w której każdej osobie wylosowałem jeden z ze środków transportu. Nie przejmowałem się na tym etapie tym, od jakiego wieku można prowadzić samochód.

Instrukcja if-else

Wiemy już skąd się wzięli klienci, których zobaczyłeś w barze, i ich środek transportu. Teraz najważniejsze: skąd barman wiedział, komu może sprzedać coś mocniejszego?

Użyłem do tego instrukcji warunkowej if-else – jednej z podstawowych w wielu językach programowania. Jej działanie jest dokładnie takie, jak wynika z tych instrukcji:

jeżeli coś jest prawdą:
    zrób to # instrukcja 1
w pozostałych przypadkach:
    zrób coś innego # instrukcja 2

W instrukcji takiej definiujemy warunek, który może przyjąć wartość logiczną „prawda” (czyli True) lub „fałsz” (False). Jeżeli stwierdzenie jest prawdziwe, interpreter wykona pierwszą instrukcję. W każdym innym przypadku – instrukcję drugą. Ze względu na prostotę, w przykładzie każda z instrukcji zajmuje jedynie pojedynczą linijkę, ale w praktyce mogą być bardziej rozbudowane.

Dla pełnego obrazu dodam jeszcze, że nie jest to jedynie instrukcja to-albo-to. Pomiędzy ifelse możesz dodać bloki elif z dodatkowymi warunkami, które pozwolą Ci sterować programem. Ale to nei temat na dzisiaj.

W naszym przykładzie mamy dwa warunki: wiek i środek transportu. Uznałem że w kraju, do którego trafiłeś wiek, od którego można spożywać alkohol, to 20 lat. A więc witaj w Paragwaju… albo Japonii… albo na Islandii. To ostatnie może lepiej nie, skoro morze wyrzuciło Cię tam na brzeg – za bardzo byś zmarzł, a to nie szkolenie na SEALsów.

Za pomocą kodu Pythona, wiek klienta możemy sprawdzić w funkcją w ten sposób:

def check_age(age):
    '''Check if person is allowed to drink alkohol'''
    if age >= 20:
        return 'sprzedaj'
    else:
        return 'nie sprzedawaj'

Funkcja to po prostu fragment kodu, który robi zadaną mu rzecz. Żeby zdefiniować własną, musisz podać slowo kluczowe def, a potem ją nazwać. Potem taką funkcję możesz wywołać samodzielnie, wpisując na przykład:

check_age(18)
>> nie sprzedawaj
check_age(24)
>> sprzedaj

Możesz zauważyć, że pod nazwą funkcji wpisałem wiersz rozpoczynający się od trzech grawisów (”’) – to tak zwany docstring, który mówi czytającemu kod, co dana funkcja robi.

Drugim warunkiem stawianym przez barmana, co zaznaczyłem już wcześniej, jest przybycie do baru środkiem transportu, którym klient nie kierował. Możemy to sprawdzić następującym kodem:

def check_transport(mode, forbidden_transport):
    '''Check if clients mode of transport allows to drink alkohol'''
    if mode in forbidden_transport:
        return 'nie sprzedawaj'
    else:
        return 'sprzedaj'

Tutaj przerwę na chwilę, bo muszę zadać Ci ważne pytanie, zanim przejdziemy dalej: czy na podstawie danych podanych we wstępie odgadłeś, że takie są warunki sprzedaży alkoholu?

Decyzja barmana

Wracając do naszego barmana, możemy złożyć obydwie procedury napisane powyżej w jedną, która odwzorowuje decyzję, jaka zapada za kontuarem. Możemy w tym celu wykorzystać wcześniej zapisane funkcje:

def barman_decission(age, transport, forbidden_transport):
  '''Determines barman's decission on alkohol sale based on input data provided as age: int, transport: str.'''
  if check_age(age) == 'sprzedaj':
    return check_transport(transport, forbidden_transport)
  else: return 'nie sprzedawaj' # nie musimy sprawdzać środka transportu, jeśli klient jest zbyt młody

Teraz możemy zastosować opracowaną procedurę na naszej ramce danych z zamówieniami i zapisać wynik w kolumnie o nazwie decyzja:

orders['decyzja'] = orders.apply(lambda row: barman_decission(row['wiek'], row['transport'], transport_no), axis = 1)
orders

Proste, prawda? Jeśli chciałbyś poczytać więcej o podstawowych konstrukcjach w Pythonie, polecę Ci książkę „Python. Instrukcje dla programisty”, od której sam zacząłem naukę tego języka. Jeśli nie czujesz się w temacie wystarczająco pewnie albo chcesz nauczyć programowania swoje dzieci, bardzo fajna jest książka „Hello World. Wprowadzenie do programowania dla dzieci i absolutnie początkujących”. (obydwa linki są afiliacyjne – wejdziesz na stronę klikając w nie, dostanę 5% od wartości Twoich zakupów)

Automatyzacja

Dużo wyżej poprosiłem Cię o przewidzenie decyzji barmana dla 10 następnych osób, które złożyły zamówienie. Za chwilę zobaczymy, jak z tym zadaniem poradziła sobie nasz algorytm uczenia maszynowego (machine learning – ML). Żeby to zrobić, musimy najpierw wprowadzić te dane do skryptu i obrobić je dokładnie tak samo, jak wcześniej wprowadziliśmy zbiór uczący. Tym razem nie będę Cię zmuszał do wpisywania tego „z palca”, tylko wykorzystamy wiedzę z poprzedniej sekcji.

Żeby wygenerować zbiór danych do przetestowania algorytmu (i zapisać go w ramce danych o nazwie orders_test), możesz wykorzystać poniższy kod:

np.random.seed(32) 
orders_test = pd.DataFrame(np.random.randint(15,85,size = 10), columns = ['wiek'])
orders_test['transport'] = np.random.choice(transport_no+other_transport, size = len(orders))
orders_test

Taki zapis naszych danych musimy teraz przygotować pod algorytm, powtarzając kroki z poprzedniej części wpisu. Najpierw przygotujemy funkcję, która rozbije kolumnę z podanym środkiem transportu na kilka osobnych, z wartościami 0 lub 1.

def prepare_dataset(df):
  '''Prepares a dataset for decission tree algorithm'''
  df = pd.concat([df, pd.get_dummies(df.transport)], axis=1)
  df = df[['wiek', 'komunikacja miejska', 'pieszo', 'samochód', 'taxi', 'rower']]
  return df

Na tak przygotowanym zestawie danych zastosujemy nasz algorytm, który wyda decyzję co do sprzedaży alkoholu danej osobie. Odpowiedzią będzie wartość 0 (nie sprzedawaj) lub 1 (sprzedaj), ponieważ do tego wytrenowaliśmy model. Żeby łatwiej było nam się zorientować w wyniku, od razu przygotujemy funkcję tłumaczącą tę liczbę na zapis słowny.

def translate_decissions(df, column):
  '''Changes 0-1 output in df column (provided as string) into information on sale decision'''
  df[column] = df[column].map({1: 'sprzedaj', 0: 'nie sprzedawaj'})
  return df

Będziemy też potrzebowali informacji, co danej osobie odpowiedział barman – uzyskamy to z funkcji, którą przed chwilą:

def add_decission(df):
  '''Adds column with barman's decission to the dataframe'''
  df['decyzja barmana'] = df.apply(lambda row: barman_decission(row['wiek'], row['transport'], transport_no), axis = 1)
  return df

Na koniec poprosimy interpreter o porównanie wyniku naszego drzewa decyzyjnego i odpowiedzi udzielonej przez barmana. Ponieważ proste porównanie zwróci nam odpowiedź jako True (prawda) lub False (fałsz), od razu przetłumaczymy to na odpowiedź „tak” lub „nie” mówiącą, czy obydwie metody zwróciły taki sam wynik.

def compare_output(df, AI_output, expected_output):
  '''Compares AI output with expected for the record'''
  df['wynik poprawny?'] = (df[AI_output] == df[expected_output])
  df['wynik poprawny?'] = df['wynik poprawny?'].map({True: 'tak', False: 'nie'})
  return df

W końcu, wszystkie powyższe procedury zbiorę w jedną, pozwalającą nam wykonać wszystkie operacje jedną komendą.

def workflow_bar(df):
  '''Applies workflow comparing decission tree and barman's decission on dataset provided in a DataFrame'''
  df_prepared = prepare_dataset(df) # przygotuj dane do analizy i zapisz je w osobnej ramce danych
  df['wynik drzewa decyzyjnego'] = dtc.predict(df_prepared) # zapisz wynik działania algorytmu drzewa decyzyjnego dla każdego z rekordów
  df = translate_decissions(df, 'wynik drzewa decyzyjnego') # zmień liczbowy wynik działania algorytmu na opis słowny
  df = add_decission(df) # zastosuj algorytm decyzji barmana na każdym rekordzie
  df = compare_output(df, 'wynik drzewa decyzyjnego' , 'decyzja barmana') # porównaj wyniki uzyskane obydwoma metodami
  return df

Teraz jesteśmy gotowi, żeby sprawdzić, jak radzi sobie nasz algorytm.

Egzamin dla sztucznej inteligencji

No, to nie zostaje nam już nic innego, jak tylko zastosować naszą funkcję na przygotowanych danych:

orders_test = workflow_bar(orders_test)

Jeśli dokładnie powtórzyłeś mój kod, powinieneś zobaczyć taką tabelę.

indexwiektransportwynik drzewa decyzyjnegodecyzja barmanawynik poprawny?
058rowernie sprzedawajnie sprzedawajtak
120pieszosprzedajsprzedajtak
269komunikacja miejskanie sprzedawajsprzedajnie
377samochódnie sprzedawajnie sprzedawajtak
434pieszosprzedajsprzedajtak
518pieszonie sprzedawajnie sprzedawajtak
624pieszosprzedajsprzedajtak
719taxinie sprzedawajnie sprzedawajtak
826pieszosprzedajsprzedajtak
918taxinie sprzedawajnie sprzedawajtak

Wśród 10 klientów, nasz wytrenowany algorytm odmówiłby drinka jednemu pełnoletniemu klientowi, który przyjechał komunikacją miejską. W pozostałych ośmiu przypadkach, wydałby decyzję taką samą, jak troskliwy i profesjonalny barman. Czy to dobrze, czy źle?

Na razie oceń sam. Ja szerzej opowiem co to znaczy, że algorytm radzi sobie dobrze w następnym wpisie z serii (przed którym planuję jeszcze wpis na temat kreatywności). Jeśli nie chcesz go przegapić, zostaw mi swój adres e-mail:

Zapisując się na newsletter wyrażasz zgodę na przetwarzanie Twoich danych osobowych zgodnie z polityką prywatności w celu otrzymywania powiadomień o nowych wpisach i wydarzeniach związanych z blogiem. Nie będę Cię spamował. Będziesz mógł w każdej chwili zrezygnować z subskrypcji.

Zwiększamy skalę

Chciałem pokazać Ci działanie uczenia maszynowego na prostym przykładzie, ale dokładnie tak samo wygląda uczenie sztucznej inteligencji w bardziej skomplikowanych przypadkach. Algorytm pomagający Ci jako asystent głosowy w komórce, kierujący samochodem autonomicznym, dobierający parametry zdjęcia w Twoim telefonie, analizujący zdjęcia rentgenowskie czy obrazy tomograficzne, generujący zdjęcia ludzi czy obrazy – wszystkie powstają w ten sam sposób. Trzeba wybrać (i często zaprogramować od zera, a nie skorzystać z „gotowca”, jak w tym wpisie) rodzaj algorytmu, zebrać i przygotować dane uczące (często w tysiącach czy milionach obserwacji), nauczyć algorytm i sprawdzić, jak się sobie radzi na danych testowych, nanieść poprawki – i tak w kółko, aż nie uznamy, że nasz algorytm radzi sobie dobrze.

A co to znaczy, że radzi sobie dobrze? O tym napiszę w następnym wpisie, bo ten się już baaardzo rozrósł. W międzyczasie, możesz podesłać ten wpis znajomym, żeby też nauczyli się czegoś o AI. Czekam też na Twoje komentarze pod nim!