Göm meny

Temauppgift 3

I denna temauppgift kommer ni att bearbeta data som ni även använder i kursen 729G03 Forskningsmetodik och statistik. Ni kommer dels använda Python för beräkna ny kolumndata, men också använda python för att visualisera data i olika typer av diagram.

Nyckelbegrepp

dictionary, nästlad struktur, filläsning, csv

Inlärningsmål

Syftet med denna temauppgift är att du ska få dels se hur Python kan användas som ett verktyg för att dels bearbeta data, men också för att visualisera data i interaktiva diagram. Uppgiften kopplar till följande kursmål:

Efter avslutad kurs ska den studerande kunna:

  • förklara grundläggande informationsteknologiska begrepp och vilken koppling dessa har till kognitionsvetenskap och ämnesområden som är relevanta för en kognitionsvetare
  • förklara programkod de själva och andra på kursen skrivit
  • använda grundläggande datatyper/datastrukturer och styrstrukturer för att skriva enklare program

Muntlig redovisning

Labben redovisas vid särskilt redovisningstillfälle, se deadlines.

Komplettering

Missad redovisning kompletteras genom att skicka in en screencast där du demonstrerar ditt program (berätta vad som händer och vilken kod som anropas) samt svarar på de frågor som finns i slutet av denna sida.

Du behöver inte redigera screencasten på något speciellt sätt. Se bara till att det du vill visa syns, samt att din röst hörs. Screencasten får vara max 10 minuter lång.

Uppgiftsöversikt

Dela upp ert arbete på följande sätt:

  1. Läs igenom hela denna sida innan ni börjar (precis som att det kan vara bra att läsa igenom hela receptet innan man börjar laga maten, då slipper man överaskningar som t.ex. “låt vila i 8 timmar”).
  2. Skriv ner på papper vad ni måste göra med er data för att få fram den information ni behöver leverera till chartmaker (se nedan)
  3. Gör en uppgift i taget, testa er kod regelbundet - det är lättare att rätta få fel än många fel.

Uppgifter markerade med VG behöver endast göras om du siktar på att få VG på temauppgiften.

Allmänna tips - dela upp din kod i funktioner

Dela upp din kod i funktioner, på så sätt kan du återanvända kod. När du i uppgift 2 t.ex ska ladda in data från CSV-fil till en lista. Skriv denna som en funktion som du kan återanvända senare.

Att dela upp koden i funktioner gör också att du kan ha en tydligare huvudfunktions där koden mest består av anrop till andra egna funktioner. Om du döper dessa funktioner väl, blir det lätt att läsa huvudfunktionen och få en överblick över vad som händer.

Även om man inte kan sätta en exakt siffra på det, bör du kunna hålla längden på koden i de olika funktionerna under 20 rader, oftast kortare. Försök att skriva din kod så att varje funktion (förrutom huvudfunktionen) bara gör en sak.

Filer att kopiera från kurskatalogen

CSV-filer

I mappen ~729G74/kursmaterial/temauppgift3/csv finns råfiler till det dataset som ni använder er av i kursen 729G03 - Statistik och forskningsmetodik. Data för varje enskild försöksperson finns sparad i en enskild fil, t.ex. sub1.csv för försöksperson 1.

Kolumnerna i CSV-filerna är följande:

  1. Trial (uppgiftsnummer för FP)
  2. Bildfil/parametrar för figurparet som visades
  3. FPs responstid
  4. Förväntat svar ("[b]" betyder att bilderna är lika, "[n]" betyder att bilderna är speglade).
  5. FPs svar
  6. Antal grader som figuren roterats.

Dessa är rådatafiler konverterade från Excel till csv med vissa rader och kolumner borttagna för att göra bearbetning enklare1.

chartmaker.py

I mappen ~729G74/kursmaterial/temauppgift3/ finns filen chartmaker.py. Den innehåller funktioner som tar emot ett dictionary med data på ett specifikt format och använder den för att generera diagram. Diagramen sparas till en html-fil som ni kan öppna i en webbläsare. Pythonpaketet bokeh används för att skapa detta.


  1. Du kan se konverteringsskriptet i ~729G74/kursmaterial/temauppgift3/. Konverteringsskriptet är ett shellscript som både använder vanliga Linux-kommandon, samt pythonopaketet xlsx2csv. [return]

Uppgift 1: Ta emot argument, importera modul

Att göra

  • kopiera chartmaker.py
  • skriv skript som skriver ut argument och testar att chartmaker-modulen fungerar som den ska (använd rätt virtualenv)

Detaljer

Börja med att kopiera filen chartmaker.py från kurskatalogen (se ovan) till den katalog ni tänk jobba i.

Ni behöver också aktivera den virtualenv som innehåller bokeh-paketet. Gör detta genom att skriva

$ source ~729G74/kursmaterial/python/tuvenv/bin/activate

Skapa ett skript som:

  • importerar chartmaker-modulen (import chartmaker utan .py)
  • kör funktionen chartmaker.test() för att se att allt fungerar där
  • skriver ut de argument som ni anger när ni anropar skriptet

Exempel på körning av detta skript (chartmaker.test() skriver ut raden själv):

$ ./temauppgift3.py hej hopp
hej
hopp 
chartmaker: allt verkar fungera.

Se lektionsövning 0 för tips och hjälp.

Uppgift 2: ladda in data från CSV, skapa diagram

Att göra

  • ladda in data från csv-fil (argument till skript)
  • skicka data på rätt format till chartmaker.single() som skapar en html-fil med diagram som du kan titta på i en webbläsare.

Detaljer

Nästa steg är att ladda in data från en csv-fil. Här ska vi göra det genom att du anger namnet på filen som ett argument i anropet till skriptet.

Säg att du kopierat alla csv-filer till mappen data som ligger i samma katalog som ditt skript. Då ska skriptet kunna ta emot ett filnamn påföljande sätt via anrop:

$ ./temauppgift3.py data/sub1.csv

Data från CSV-filen läser du till en nästlad lista. Denna lista stoppar du in i ett dictionary under nyckeln "orig" och skickar sedan dictionaryt till chartmaker.single()1. Lagra även namnet på filen i detta dictionary under nyckeln "filename".

Nedan följer exempel på hur de första raderna i listan ska se ut (för sub1.csv) samt ett skelett till pythonskriptet. CSV-data från sub1.csv i som nästlad lista (första 6 raderna):


[['1', 'R2_3_3_2_0Y0.pct', '1355', '[n]', '[n]', '0'],
 ['2', 'R3_4_3_2_90Y150.pct', '2079', '[n]', '[n]', '150'],
 ['3', '2_4_4_2_0Y150.pct', '1834', '[b]', '[b]', '150'],
 ['4', '3_3_3_2_0Y100.pct', '4780', '[b]', '[b]', '100'],
 ['5', '3_3_3_3_90Y50.pct', '1685', '[b]', '[b]', '50'],
 ['6', 'R2_4_4_2_0Y50.pct', '1237', '[n]', '[n]', '50']]

Kodsnutt med exempel på hur chartmaker importeras och chartmaker.single() anropas.


import sys
import chartmaker

# ladda in data från CSV, definitioner av funktioner och variabler inte
# med i detta exempel.
data = load_csv(filename)
chartdata = { "orig": data, "filename": filename }

# skapa diagram
chartmaker.single(chartdata)

Det är en bra idé att skriva en funktion som tar in ett namn på en fil och som returnerar en lista i formatet ovan.


  1. chartmaker.single() tar ett argument, men detta utelämnas i instruktionerna (precis som man gör i mycket annan dokumentation som inte just är API dokumentation. [return]

Uppgift 3: klassificera fel, filtrera data, kolumnbaserad datastruktur

Att göra

  • 3a: klassificera feltyper och lägg till denna information
  • 3b: skapa en funktion som “roterar” radbaserad struktur till en kolumnbaserad struktur
  • 3c: skapa filtrerad lista som bara innehåller felen
  • skicka data som bara innehåller fel, samt ofiltrerad data till chartmaker.single()

Detaljer

Uppgift 3a. Klassificering

Du ska nu lägga till en extra kolumn i datat. Kolumnen ska klassificera försökspersonens respons som sann positiv, falsk positiv, sann negativ eller falsk negativ. Använd följande strängar som värden: "tp", "fp", "tn", "fn" (som i true positive, false positive etc).

Om vi tänker oss att frågan försökspersonen fick var “Är den ena figuren speglad?” får vi följande klassificeringar:

  • b & b: tn
  • b & n: fp
  • n & b: fn
  • n & n: tp

Om en respons saknas använder du "N/A" som värde.

Följande är ett visar några klassificerade rader:

[['8', '2_3_3_2_0Y0.pct', '1275', '[b]', '[b]', '0', 'tn'],
 ['9', 'R3_4_3_3_180Y150.pct', '4716', '[n]', '[n]', '150', 'tp'],
 ['10', 'R3_4_3_3_180Y150.pct', '4716', '[n]', '[n]', '150', 'tp'],
 ['11', '2_4_4_2_180Y150.pct', 'N/A', '[N/A]', '[b]', '150', 'N/A']]

Skriv en funktion som tar in data i det format som vi använde i förra uppgiften (Uppg. 2) och returnerar en en ny lista med klassificering enligt ovan.

OBS! Se till att du inte ändrar i data som tillhör föregående uppgift, utan istället skapar en ny lista med data som ska tillhöra denna uppgift. Annars kan du få klagomål från chartmaker.single() om att den förväntade sig data med 6 kolumner, men att den inte fick det.

Uppgift 3b. Kolumnbaserad liststruktur

Skriv en funktion som tar data med samma struktur som i föregående uppgift (csv-data med klassificering) och returnerar ett dictionary med datat i kolumnerna enligt nedan. För att göra detta lättare, skriv också en funktion som tar in en radbaserad liststruktur och returnerar en kolumnbaserad liststruktur.

CSV-formatet lagrar varje rad i en tabell som en textrad. Ett annat sätt hade varit att lagra varje kolumn som en textrad istället. Detta sätt att strukturera data lämpar sig bra för att lagra en tabell som ett dictionary istället. Nycklarna i dictionaryt kan då användas för namnen på kolumnerna. Se nedan för ett litet exempel (ej riktig data):


table_columns = { "trial": ['1', '2', '3', '4'],
                  "condition": ["2_4_4_2_0Y150.pct", "2_4_4_2_0Y150.pct",
                                "2_4_4_2_0Y150.pct", "2_4_4_2_0Y150.pct"] 
                  "time": ['1000', '1100', '1200', '1150'],
                  "system": ['[b]', '[b]', '[n]', '[b]'],
                  "user": ['[b]', '[b]', '[b]', '[n]'],
                  "angle": ['0', '0', '50', '100'],
                  "response": ["tn", "tn", "fn", "fp"] }

Vi behöver skicka informationen till chartmaker på denna form. För att detta ska vara lättare att göra, skriv en funktion som tar en radbaserad listastruktur och returnerar en kolumnbaserad liststruktur1. Se exempel nedan.

Radbaserad liststruktur (varje lista är en rad):

[ [ 1,  2,  3,  4],
  [11, 22, 33, 44] ]

Kolumnbaserad liststruktur (varje lista är en kolumn):

[ [1, 11], [2, 22], [3, 33], [4, 44] ]

I den här uppgiften ska du skriva funktionen genom att använda nästlade loopar!

När du skrivit funktionen som roterar den radbaserade liststrukturen kan du enkelt skapa ett dictionary med kolumnrubriker (nycklarna) och kolumndata (hämta en kolumn och lagra den i ett dictionary under rätt nyckel).

Du kan nu skicka in denna data till chartmaker.single() om du vill. Lägg in den under nyckeln "classified data":

chartmaker.single({ "filename": filename,
                    "orig": orig,
                    "classified data": classified_columns })

Uppgift 3c. Filtrera listan

Vi ska göra ett diagram som visar vilka feltyper som gjorts, under vilka omständigheter och hur många gånger.

Skriv en funktion som tar in csvdata med samma struktur som i föregående uppgift (radbaserad lista med csv-data med klassificering) och returnerar en lista med endast rader med felaktiga responser (falsk negativ fn och falsk positiv fp).

För att kunna skicka denna filtrerade lista till chartmaker behöver den också göras om till ett dictionary med kolumndata som listor under nycklar. Följande kolumner ska finnas med (använd denna exakta stavning):

  • "trial"
  • "time"
  • "angle"
  • "response"

Lägg till detta dictionary till det dictionary du skickar till chartmaker.single() under nyckeln "only errors":

chartmaker.single({ "filename": filename,
                    "orig": orig,
                    "only errors": filtered_column_data,
                    "classified data": classified_columns })

"only errors" är alltså ett det kolumnbaserade dictionaryt som bara innhåller data från rader där responsen varit "fp" eller "fn"


  1. I framtiden kan du använda följande kod för att “rotera” en lista som innehåller listor av lika längd som vi har i vårt fall: rotated = list(zip(*csvdata)). [return]

Uppgift 4: En massa diagram

I denna uppgift ska ni applicera alla steg ni gjorde i uppgift 2-3 på flera filer. Data för alla dessa filer ska skickas till chartmaker.multiple() som då kommer generera en visuell överblick över alla filer.

Att göra

  • skapa nytt skript
  • importera gamla koden med import
  • gör det möjligt för skriptet att ta emot ett godtyckligt antal argument (filnamn)
  • läs in data från flera filer, skapa översikts-diagram med chartmaker.multiple()

Detaljer

Skapa ett nytt skript som istället för att ta in namnet på en fil, tar in namnet på ett godtyckligt antal filer. För att återanvända koden från de tidigare uppgifterna importerar du ditt tidigare skript som en modul.

På detta sätt kommer du åt funktionerna du skrev förut. Här blir det också viktigt att du har anropen som kör dina funktioner “skyddade” bakom en if __name__ == "__main__".

Ta emot godtyckligt antal argument

När du importerat din “gamla” kod, börja med att göra så att skriptet skriver ut alla argument den får. Prova med att anropa den med följande från skalet:

$ ./nytt-skript.py *.*

När man skriver *.* i skalet och anger det som argument kommer skalet att expandera detta uttryck så att kommandot får alla filnamn som matchar uttrycket som argument och inte *.*. Ta reda på några andra specialtecken man kan använda sig av i skalet för att matcha filnamn (googla på wildcard glob bash).

Processa flera CSV-filer

Nästa uppgift är att är att för varje fil som skriptet får in, skapa ett dictionary med processad data, precis som du gjorde i uppgift 2-3. Skillnaden här är att du lägger dessa dictionaries i en lista och skickar den listan till chartmaker.multiple() som kommer att skapa diagram för alla dessa.

chartmaker.multiple() ska alltså ta emot en lista av dictionaries.

Tillägg: Du kan också prova skicka dictinaryt till chartmaker.multiple_heatmaps(), chartmaker.multiple_time_errors() eller chartmaker.multiple_time_angles() för andra diagram.

Uppgift 5: Aggregera data från flera filer (VG)

VG uppgiften för denna temauppgift är att skriva ett tredje skript som tar in flera filnamn som argument precis som ovan, men som sammanfattar varje fil i en rad. Raderna för de olika filerna läggs sedan i en lista.

Att göra

  • läs in alla filer och skapa ett dataset som innehåller en rad för varje försöksperson.

Varje försökspersons rad innehåller snittet av personens data. Följande kolumner ska finnas för varje person:

  • numeriskt id för försökspersonen (använd del av filnamnet)
  • antal försök (trials) som försökspersonen gjorde
  • en kolumn för antal fel för varje rotationsgrad, dvs en med antal fel på 0 grader, antal fel på 50 grader osv (felklassificering behövs inte)
  • en kolumn för genomsnittstiden för varje rotationsgrad, dvs en med genomsnittstiden för 0 graders rotation, en för 50 grader etc.

Detta dataset kommer i princip innehålla samma data som ni använder er av i 729G03.

Uppgift 6: Eget diagram (VG)

Den sista VG uppgiften är att skapa ett diagram med hjälp av bokeh för datat du aggregerade i uppgift 5. Du behöver inte göra någon speciell typ av diagram, utan det räcker med att göra ett linjediagram för t.ex. alla genomsnittstider för 0-graders-försöken.

Se lektionsövningarna för vägledning.

Frågor

Följande frågor ska kunna besvaras efter genomförd uppgift:

  1. Hur använder man kod från en annan fil som en modul?
  2. Vad gör raden if __name__ == "__main__":?
  3. Hur skickar man in argument till ett skript?
  4. Hur skickar man in alla filnamn som t.ex. börjar på "uppg" till ett skript eller kommando i skalet?


Sidansvarig: Jody Foo
Senast uppdaterad: 2017-10-27