Monty Hall Pythonilla

Luin Dimensiosta Hannu Korhosen kirja-arvion Tapio Lindin Vesimelonin kuivatus ja muita matemaattisia pähkinöitä -kirjasta. En ole vielä ehtinyt lukemaan kirjaa, mutta se pitänee lukea lähiaikoina. Kirjassa yhtenä ongelmana on kuuluisa Monty Hall-probleema. Aihe on kuikertanut mielessäni jo jonkin aikaa. Niinpä päätin tehdä siitä pienen Python ohjelman. Lähinnä itselleni ja samalla myös oppilaitani varten esimerkkinä siitä, miten sanallinen ongelma käännetään tietokoneohjelmaksi.

Ongelma sanallisesti

Wikipediassa Monty Hall -ongelma esitetään seuraavasti: ” Monty Hallin ongelmassa kilpailijalla on edessään kolme ovea. Yhden oven takana on palkintona auto, kahden muun takana vuohi. Kilpailija, joka ei tiedä minkä oven takana mikin palkinto on, saa valita ovista yhden. Valittuaan oven hän ei vielä avaa sitä. Jäljelle jääneistä kahdesta ovesta avataan toinen, ja sen takana on aina vuohi. Tämän jälkeen kilpailija saa valita, vaihtaako ensin valitsemansa oven toiseen jäljellä olevaan suljettuun oveen, vai pitääkö ensin valitsemansa oven.”

Varmaankin kaikki matikan opet tietävät (viimeistään lukemalla ratkaisun Wikipediasta), että kilpailijan kannattaa vaihtaa, sillä pitämällä ensimmäisen valinnan, niin todennäköisyys voittoon on 1/3 ja vaihtamalla 2/3.

Python koodi

Tehdään Pythonilla ohjelma, joka noudattaa edellä esitettyä tilannetta siten, että kilpailija vaihtaa aina valintansa. Koodia kirjoittaessa en käytä järkeä siinä mielessä, että oikaisisin suoraan ratkaisuun. Toteutan tilanteen ikään kuin ohjeen mukaan. Laitan koodiin rivinumerot ja kommentit, joiden avulla yritän kertoa lukijalle mitä koodissa tapahtuu.

Muutama kommentti koodista

Lukijan on hyvä muistaa, että Pythonissa listan ensimmäisen jäsenen järjestysluku on nolla, toisen järjestysluku on 1 jne. Siksi ovien numerot ovat 0, 1, ja 2.

Rivillä 9: shuffle(lista) funktio sekoittaa syötelistansa jäsenet satunnaisesti.

Rivillä 13: randint(a, b) tuottaa satunnaisen kokonaisluvun väliltä [a, b].

Rivillä 17: pop-metodi poistaa olion listasta ja antaa sen tulosteena.  Jos lista  = [13, 42, 666, 42], niin lista.pop(1) antaa tulokseksi luvun 42 ja samalla listasta katoaa jäsen 42, eli nyt lista on [13, 666, 42].

Rivillä 20: remove-metodi poistaa ensimmäisen esiintymän syötteestään. Jos lista  = [13, 42, 666, 42], niin lista.remove(42) muutaa listan listaksi [13, 666, 42].

Rivillä 23: Leikkauksien avulla saadaan valittua listasta jäseniä. Jos lista on lista  = [13, 42, 666, 42], niin lista[1] tulostaa luvun 42.

Alla ohjelman tuottama tulos muutamalla suorituskerralla.

Kun tuota ohjelmaa ja tulosteita katsoo, niin pikku hiljaa (ainakin minulle) selkenee, että tässä pelissä pelaaja voittaa, jos hän on alun perin valinnut vuohen. Vuohi valitaan todennäköisyydellä 2/3.

Tehdään vielä ohjelmaan sellainen muutos, että suoritetaan se vaikkapa 1000 kertaa ja lasketaan voittojen lukumäärä.

Alla ohjelman tulos:

Seuraavassa tarinassani muokkaan ongelmaa/ohjelmaa sellaiseksi, että vuohia onkin vaikkapa 5 ja voittoautoja 2. Ja samalla tietysti pohdin, mikä siinä tilanteessa on voiton todennäköisyys.

Lähteet

https://dimensiolehti.fi/kirjallisuutta-vesimelonin-kuivatus/

https://fi.wikipedia.org/wiki/Monty_Hallin_ongelma

 

Kevät 20 pitkän matikan tehtävä 12.2 GeoGebralla

[edit 23.3. Lisäsin tarinan loppuun pari eri tapaa ratkaista tehtävän ja kuvan pisteistä.]

Kevään 20 pitkän matikan tehtävässä piti selvittää luonnollisiin lukuihin liittyvä lukumäärälasku. Tämähän on meille ATKnörteille simppeli ohjelmointiongelma.


Jollain ”oikealla” ohjelmointikielellä tuo taitaa olla muutaman rivin ohjelma. Ratkaistaan 2.-kohta GeoGebralla. Tässä tulee 100*100 lukua eli ei kannata käyttää CASia, veikkaan, että kone hyytynee. Käytetään Algebra-ikkunaa. Teenpä tämän GeoGebra 6:lla ihan testatakseni miten se toimii. Kokeilin tätä GG 5:llä ja tehtävä ratkesi ihan OK, mutta ohjelma alkoi himpun verran jumittaa koska listan koko on 10000.

Komento

Jono(Jono(sqrt(a b), a, 1, 100), b, 1, 100)

tuottaa listan matriisin m1. GeoGebra 5:ssä Algebraikkunassa matriisi näkyy matriisin näköisenä, GG6:ssa voi arvata, että se on matriisi sillä alussa näkyy kaksi kaarisulkua. Toisaalta sisäkkäiset Jono-komennot tuottavat aina matriiseja. Matriisin m1 pituus (eli oikeasti m1 listan pituus saadaan komennolla

Pituus(m1)
-> 100

tuottaa luvun a = 100. Matriisin sisällä olevat ”turhat” kaarisulkeet saa pois Tiivistä-komennolla

Tiivistä(m1)

tuottaa listan l1, jonka pituus on

b = Pituus(l1)
-> 100

Selvitetään, mikä näistä luvuista on luonnollinen luku. Ehto

floor(luku) == luku

antaa tulosteeksi true, jos luvun kokonaisosa on yhtäsuuri kuin luku itse eli onko luku kokonaisluku. Käydään läpi kaikki luvut listassa l1 ja tutkitaan mitkä ovat luonnollisia lukuja

l2 = Zip(Jos(floor(aa) == aa, aa), aa, l1)
-> {1, ?, ?, 2, ?, ...

Nuo kysymysmerkit vastaavat niitä lukuja, joilla ehto ei ole voimassa. Poistetaan määrittelemättömän lista oliot eli nuo kysymysmerkit komennolla

l3 = PoistaMäärittelemätön(l2)
-> {1, 2, 3, 4, ...
c = Pituus (l3)
-> 310

Kysytty todennäköisyys on

d = c/b

-> 31/1000

GeoGebra 6:ssa isojen listojen käsittely tuntuu sutjakkaammalta kuin GeoGebra 5:ssä. Tosin molemmissa ohjelmissa ratkaisu onnistui MacBookissani.

Lisäys 22.3.20

En malttanut olla kokeilematta paria muuta tapaa. Idea tuli Edwardilta Facebookista.

m2 = Jono(Jono(Jos(floor(sqrt(a b)) ≟ sqrt(a b), 1, 0), a, 1, 100), b, 1, 100)

tuottaa lista, matriisin, jossa on paljon nollia ja ykkösiä.

l5=Summa(m2)

tuottaa lista, jossa on vaakarivien summat {10, 7, …

Summa(l5) = 310

Toisaalta yhdellä rivillä

Jono(Jono(Jos(floor(sqrt(a b)) ≟ sqrt(a b), 1, 0), a, 1, 100), b, 1, 100) = 310

Jos olisi halunnut nuo pisteet koordinaatistoon, niin sen saa komennolla

Jono(Jono(Jos(floor(sqrt(a b)) ≟ sqrt(a b), (a, b)), a, 1, 100), b, 1, 100)

Opeapu, taulukkolaskentasovellus

Olen käyttänyt noin 30 vuotta oppilasarvioinnin apuna taulukkolaskentasovellusta nimeltä opeapu. Viimeisimmän muutoksen tein tammikuussa 18 kun opiskelin Google Apps scriptausta sen verran, että saan arvioinnin tuloksen lähtemään automaattisesti sähköpostitse oppilailleni.

taulukkolaskennasta_PDF__sivu_49___57_.png
Kuvankaappaus kottaraispönttötyylisestä MacIntoshista noin vuodelta 1991

Tietokoneeni uumenista löytyy 50 sivuinen pdf-tiedosto: Lavonen, Rahikka, Voipio. Taulukkolaskennasta fysiikan opetuksessa. Se on MAOL ry:n fysiikan toimikunnan raportti vuodelta 1992. Raporttia ei ole julkaistu kokonaisuudessaan missään, mutta osia siitä julkaistiin 90-luvun alkuvuosina Dimensiossa. Raportissa on Excelin käytön ohje, runsaasti erilaisia esimerkkejä fysiikan opetukseen liittyen: mittaustulosten käsittelyä, suorien ja käyrien sovittamista, yhtälöryhmien ratkaisua, simulointeja, matriisilaskentaa. Siellä on selitetty myös oppilasarvioinnin apuvälineen toiminta. Valitettavasti suurin osa esimerkkitiedostoista on kateissa.

Ajan myötä olen tehnyt opeapusta monta versiota eri taulukkolaskentaohjelmille. Aluksi käytin sitä Macissä toimivalla Ragtime-ohjelmalla. Aika pitkään arvioin oppilaita Appleworks-versiolla kunnes siirryin Excel-versioon. Viimeinen suurempi muutos oli, kun koulumme siirtyi Googlen käyttäjäksi, niinpä nykyisin käytän Google Sheets-versiota.

Opeapun idea on yksinkertainen. Laitan oppilaiden kokeesta ja muista tehtävistä saadut pisteet taulukkoon, määritän kunkin tuotoksen painokertoimet sekä  arvosanoja 4 ja 10 vastaavat pisteet. Ohjelma tuottaa kullekin oppilaalle arvosanan. Tässä viimeisessä versiossa ohjelma myös lähettää sähköpostia kullekin oppilaalle kertoen tietoa arvioinnista ja lopullisen arvosanan.

Opeapu_emaililla_jakoon_-_Google_Sheets
2018 versio sovelluksesta

Nykymuodossaan sovellus on oheisen kuvan näköinen. Kurssin arviointi menee käytännössä seuraavasti.

Kopioin Wilman arviointilomakkeelta oppilaiden nimet ja luokat. Sijoitan ne solusta C10 lähtien C ja D sarakkeille. Kokeesta saadut pisteet sijoitan F-sarakkeelle ja Classroomtehtävien pisteet J-sarakkeelle. Mahdolliset muut tuotokset laitan omille sarakkeilleen. Oppilaiden sähköpostiosoitteet saan kopioitua Google Classroomin arviointilomakkeesta. Kunkin tuotoksen pistemäärän painokertoimet laitan alueelle F8:L8. Lopulta päätän millä pistemäärällä kurssin läpäisee (solu D5) ja millä saa arvosanan 10 (solu E5). Sitten valitsen Sheetsin valikosta Työkalut → Ohjelman muokkaustyökalu → Suorita

Oppilaat saavat sähköpostiviestin:

Tässä kurssin arviointi, tarkista arviointini.
 Jos epäilet arvioinnin oikeellisuutta, niin lähetä sähköpostia tai tule juttelemaan kasvokkain.
 
 
 nimi: rahikka, luokka: 42A, kurssi: FY2,
 kurssin arvosana: 9,
 koepisteet: 50, Classroom: 321, muut pisteet: 50, pisteet yhteensä: 110.54545454545455, arvosana ennen pyöristystä 9.422222.
 
 Arvosanan 10 olisi saanut pistemäärällä 120
 arvosanan 4.5 olisi saanut pistemäärällä 30.
 Suurin Classroom pistemäärä oli 321
 
 Tämä on Mikon luoman robotin luoma sähköpostiviesti, pöö.
 
 -- 
 M m@hyl.fi
 born to lose, live to win.

koodi

Google Sheetsin koodi kirjoitetaan Työkalut → Ohjelman muokkaustyökalu Koodi-ikkunaan. Oheisessa koodissa (löytyy tarinan lopusta) on lisätty rivinumerot rivien alkuun. Viittaan niihin kun selvittelen miten koodi toimii.

  • rivi 1              Funktion määrittelyn alku.
  • rivi 2              Määritellään aktiivinen taulukko/lomake.
  • rivi 3              Määritellää rivi, josta oppilaiden tietoja aletaan lukea.
  • rivi 4              Haetaan solusta A59 oppilaiden lukumäärä, solussa A59 on kaava =COUNTA(A10:A57).
  • rivi 7              Määritellään luettava tietoalue, eli solusta A10 soluun joka on oppilaiden lukumäärä – 1 verran alempana ja 14 -1 saraketta oikealle A-sarakkeesta. Esimerkissä alue on A10:N11.
  • rivi 10            Haetaan muuttujaan data edellisellä rivillä määritellyn alueen tiedot.
  • rivi 12            Tämä silmukka luo sähköpostissa tarvittavan tekstin ja lähettää sen kullekin oppilaalle rivillä 36, muuttuja i viittaa siihen riviin mitä käsitellään.
  • rivi 13            Haetaan sähköpostiosoite rivin vasemmanpuolimmaisesta solusta, luku 0 viittaa tässä sarakkeeseen A.
  • rivi 16            Alkutekstiä muuttujaan alku, \n on rivinsiirto, sen tulee olla kiinni seuraavassa sanassa.
  • rivi 17 – 26     Muuttujaan message määritellään tekstiä, joka haetaan riviltä oikeista kohdista. + merkin avulla liitetään tekstiä.
  • rivi 20            Haetaan kurssin nimi solusta A2.
  • rivi 28-32      Luodaan lisää tekstejä sähköpostiviestiin.
  • rivi 34            Sähköpostiviestin aihe.
  • rivi 36            MailApp.sendEmail-funktiolla on kolme syötettä. Ensimmäinen on sähköpostiosoite, toinen aihe ja kolmas varsinainen viesti, +:n avulla liitetään eri tekstit yhteen.
  • rivi 37            Riviltä 12 alkavan for-silmukan lopetus
  • rivi 38            Koko ohjelman lopetus.

Koodi on muokattu sivun https://developers.google.com/apps-script/articles/sending_emails ohjeesta.

 1 function sendEmails() {

 2   var sheet = SpreadsheetApp.getActiveSheet();     // eka taulukko

 3   var startRow = 10;  // eka rivi luettavasta datasta

 4   var lkm = sheet.getRange("A59").getValue();     // haen oppilaiden lukumäärän, se on counta-funktiolla laskettu soluun A59

 5 

 6 

 7   var dataRange = sheet.getRange(startRow, 1, lkm, 14);    //luettava data-alue A10:L(10+lkm)

 8  

 9  

10   var data = dataRange.getValues();  //

11  

12   for (i in data) {     // tämä silmukka hakee  tarvittavan datan ja lähettää sen rivillä 34. se käy data-alueen läpi riveittäin.

13     var row = data[i];

14     var emailAddress = row[0];  // eka sarake

15    

16     var alku = "Tässä kurssin arviointi, tarkista arviointini. \nJos epäilet arvioinnin oikeellisuutta, niin lähetä sähköpostia tai tule juttelemaan kasvokkain. \n\n\n ";

17     var message =

18     "nimi: "+ row[2]+

19     ", luokka: "+ row[3]+

20     ", kurssi: " + sheet.getRange("A2").getValue() +

21     ", \nkurssin arvosana: " + row[4]+

22     ", \nkoepisteet: " + row[5]+

23     ", Classroom: " + row[9]+

24     ", muut pisteet: " +row[5]+

25     ", pisteet yhteensä: " + row[12]+

26     ", arvosana ennen pyöristystä " + row[13]+ ".";       // varsinainen viesti

27    

28     var loppu = "\n\nArvosanan "+ sheet.getRange("E6").getValue()+ " olisi saanut pistemäärällä "+ sheet.getRange("D6").getValue();  // lisää tekstiä viestiin

29     var loppu2 = "\narvosanan "+ sheet.getRange("E5").getValue()+ " olisi saanut pistemäärällä "+ sheet.getRange("D5").getValue();

30     var cl = ". \nSuurin Classroom pistemäärä oli "+ sheet.getRange("J7").getValue()  ;

31     var ropotti = "\n\nTämä on Mikon luoman robotin luoma sähköpostiviesti, pöö.";

32     var allekirjoitus = "\n\n-- \nM m@hyl.fi\nborn to lose, live to win.";

33    

34     var subject = "Mikon kurssin arviointi, tämä on testi";

35    

36     MailApp.sendEmail(emailAddress, subject, alku + message+ loppu+loppu2+cl+ropotti+allekirjoitus);

37   }

38 }

linkit

Google sheets-tiedosto oheisella koodilla

taulukkolaskennasta fysiikan opetuksessa pdf-tiedosto