Detta är den tredje artikeln i en serie fristående artiklar som jag skrev i början av 2015 med anledning av en diskussion som uppstått kring Personuppgiftslagen (PUL) och vad som är en “databas” i lagens bemärkelse. Artiklarna är löst tematiskt sammanhållna och behandlar var för sig praktiska, juridiska och programmeringstekniska aspekter av hur man mycket enkelt kan använda en uppsättning Wordfiler som en fullt fungerande databas.
Läs även gärna de övriga artiklarna i serien:
- PUL och Worddatabaser (juridiska och politiska aspekter)
- Att skapa en databas från Wordfiler: Läsa in data (programmering och datainläsning)
- Att skapa en databas från Wordfiler: städa upp i databasen (databearbetning)
- Efterord: Liberal tolkning av PUL och bristande teknisk kunskap hos svenska domstolar? (kommer inom kort)
Inledning
I tidigare inlägg har jag diskuterat hur enkelt det är att sätta upp en databas bestående av ett antal wordfiler med hjälp av lite enkla scraping-verktyg. Men den databas vi tog fram senast är visserligen fullständig, men ganska rörig. I denna artikel visar jag hur man snabbt kan skapa lite struktur i en sådan, förhållningsvis ostrukturerad databas. Precis som i föregående inlägg kommer jag att använda mig av R för att visa hur detta kan gå till.
Skapa tidy data
Den dokumentdatabas vi skapade i förra inlägget har tre kolumner: docnum
, som fungerar som primärnyckel i databasen, header
och text
.
Vi börjar med att titta närmare på header
-kolumnen. Den visar oss vilka rubriker som finns i de olika dokumenten. Låt oss se vilka som ingår i varje dokument:
Det finns en del udda data här. Men en gemensam nämnare för nästan samtliga dokument är att de innehåller rubrikerna “Personalia”, “Ekonomi”, “Brottmål” och “Övrigt”. Ett av dokumenten, nr. 4, tycks dock ha ersatt “Ekonomi” med rubrikerna “Årsinkomster” och “Skulder”. Men det är inget vi inte kan åtgärda!
Ju större skillnaderna är mellan olika dokument, desto svårare kommer det såklart att bli att extrahera information om samtliga individer i databasen. I denna artikel gör vi antagandet att den information vi är ute efter är den som finns lagrad för samtliga individer, i detta fall uppgifter om personer, deras ekonomi (vi avgränsar oss till årsinkomster) och deras inblandning i brottmål. Dessutom kommer vi att spara alla eventuella kommentarer under “Övrigt” som en textsträng. Men vi hade lika gärna kunna varit ute efter andra data - ladda gärna ned dokumenten från mitt GitHub-repo och sök igenom dem själv!
Det viktiga nu är att skapa sig en uppfattning om hur data kan tänkas se ut. text
-kolumnen innehåller hela stycken ur de olika Worddokumenten. Vilka är relevanta, och vad kan vi utvinna för information ur dem? För att kunna svara på dessa frågor behöver vi extrahera data kategori för kategori och undersöka dem lite närmare, och eventuellt göra mindre justeringar innan vi slutligen sparar data i färdiga relationstabeller.
Nu återstår bara att söka igenom databasen kategori för kategori och spara data i ett lättläst och “tidy” format.
Personalia
Vi börjar med den lättaste kategorin - personalia. Först plockar vi ut enbart de rader som har header == "Personalia"
:
Personalia tycks vara ganska enhetligt strukturerade. Rader med namn tycks ofta (alltid?) inledas med texten “Namn:”, och personnummer följer alltid formatet YYMMDD-XXXX. Vi kan därför extrahera namn
och personnr
med hjälp av ytterligare filtrering och perl-liknande reguljära uttryck genom att söka efter de mönster jag beskrev ovan:
Vi kan nu upprepa denna procedur för alla uppgifter vi är intresserade av.
Ekonomi
Nästa steg är uppgifter om årsinkomster. Som vi såg ovan innehåller alla dokument utom ett rubriken “Ekonomi”, medan ett av dokumenten istället hade rubriken “Årsinkomster”. Vi måste alltså ta med båda två dessa i vår sökning.
Precis som ovan börjar vi med att extrahera all ekonomidata och titta närmare på den:
Vi kan notera fyra saker om vårt data:
- I vårt data har inkomstuppgifter alltid fem eller sex siffror, och ibland används ett mellanslag som tusentalsavgränsare.
- Årsuppgifter är alltid fyra siffror långa och börjar alltid med “20”.
- Inkomstuppgifter och årsuppgifter förekommer alltid på samma rad.
- Rad 17 har fem inkomstuppgifter OCH årsuppgifter på samma rad. Vi måste separera dessa till fem olika rader innan vi kan lagra dem i vårt dataset.
Vi börjar med att extrahera data för alla dokument utom nummer 5, där raden med fem inkomstuppgifter finns.
Vi fortsätter sedan med att separera inkomstuppgifter för dokument nr 5 och sedan lägga till dem till vårt nyskapade dataset.
Brottmål
Vi upprepar proceduren för brottmålsinblandning:
Det här datat har helt klart en hel del brödtext i sig. Denna hade kunnat vara intressant i något annat sammanhang men just nu är vi som sagt bara intresserade av att veta vilka brottmål personerna varit inblandade i.
Jag har ingen som helst aning om hur ett register över inblandning i brottmål kan tänkas se ut i verkligheten, men mitt intryck är att brottmålen som registreras i just dessa dokument alltid är diarieförda med en kod på formatet [X]XX-XXX, alltså två eller tre siffror följda av ett mellanslag och sen tre siffror till. Vi extraherar därför dessa data:
Kommentarer
Slutligen extraherar vi också all text som finns lagrad under “Övrigt” i dokumenten, mest för att visa att vi kan:
Sammanställning av samtliga data till en databas
Nu är vi nästan klara! Allt vi behöver göra är att lägga ihop alla de små prydliga dataset vi just skapat till en riktig, välstrukturerad databas. Som tur är har vi använt variabeln docnum
som nyckel när vi skapat alla våra småtabeller, så vi kan återanvända den för att skapa en sorts primärnyckel i vår databas.
För att se uppgifter om ekonomi eller brottmålsinblandning får vi lägga till dessa också, men om vi gör detta tappar vi principen “ett dokument, en rad”. Nedan ger jag ändå ett exempel på hur man kan göra om man vill följa principen om att lagra alla data i ett och samma dataset.
Och voila! Vi har nu skapat vår egen prydliga, välstrukturerade databas med data uppdelade per person. Databsen har en primärnyckel, är trevlig att titta på och lätt att söka i.
Som avslutning kan vi titta på två exempel på hur en sådan databas skulle kunna användas på “riktigt”, t.ex. för att göra olika typer av integritetskränkande sökningar. Låt oss först anta att vi vill veta vem som hade högst och lägst inkomster av alla personer i databasen. Vi utgår då från den senaste kända inkomstuppgiften för varje person:
Vildsvin Vildsvinsdotter är alltså den person med den högsta inkomsten i databasen, och Charlie Charlieberg är den med lägst inkomst.
Som ett andra exempel, låt oss anta att vi vill göra en scatter plot över relationen mellan inkomst och hur många brottmål man varit inblandad i. I detta fall använder vi oss av genomsnittet av personernas kända årsinkomster istället.
Så de med lägst och högst inkomster i databasen är alltså de som varit inblandade i flest brottmål. Intressant!
Avrundning
Mitt experiment där jag försökte använda en samling Worddokument som en databas är avslutat. Resultatet: det är ungefär lika enkelt att använda Worddokument som databas som det är att scrapa en webbsida, eller att lära sig lite SQL och skriva några queries. Koden i detta och föregående inlägg tog mig i runda slängar 3 timmar att skriva inklusive felsökning.
Avsikten har varit att ge ett konkret, förhoppningsvis lättläst exempel på detta. Det finns naturligtvis flera. Som jag nämnde i inledningen av detta experiment finns det nog många som skulle valt ett helt annat tillvägagångssätt men ändå nått ungefär samma, eller ett bättre, resultat.
En av poängerna jag vill göra med detta är att det är viktigt att förhålla sig kritisk till hur svårtillgänglig information faktiskt är bara för att man har lagrat den på ett obskyrt sätt. Jag tror inte att de flesta som arbetar med Worddokument har för avsikt att använda dem som en databas, men icke desto mindre är det väldigt lätt att göra just detta om man bara besitter lite rudimentära programmeringsfärdigheter.
I nästa inlägg ska jag försöka göra mitt bästa för att knyta ihop säcken kring detta resonemang.