-
Notifications
You must be signed in to change notification settings - Fork 0
/
lecture.R
375 lines (204 loc) · 9.57 KB
/
lecture.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# Data management for educational testing ---------------------------------
# You will get this file at the end, you don't need to type along!
# Goal: adopt a relational methodology for educational data
# This is something that you typically learn on the job.
# It is absolutely impossible to teach it in a 3 hour course.
# so, my apologies upfront
# Structure ---------------------------------------------------------------
# To manage educational data successfully you need to:
# 1. know how data should be stored to minimize the potential for errors
# 2. know the dimensions and requirements of your data
# 3. develop a data model
# 4. learn the necessary skills to massage real world data into your data model
# We will learn the general principles for (1)
# discus how to apply them to (2)
# Use the dexter data model in (3)
# practice with (4)
# This will all seem relatively easy until we finish with a real world assignment
# The plan is to start with this assignment no later than 11.00 so you can ask some questions
# during the first part and finish at home
# How data should be stored -----------------------------------------------
# Any questions about R4DS chapters 12 and 13?
# What does educational data look like in long / tidy form?
# principles:
# Each variable must have its own column.
# Each observation must have its own row.
# Each value must have its own cell.
# rows and columns in educational data are:
# kolommen:
# antwoorden op vragen/vragenlijsten
# versie van een toets
# school nr
#X total test scores
#X model scores/plausible values
# landen van afkomst
# student nr
# leerlinggewichten
# =>
# persoon, item, antwoord -> in tidy dat model kun je daar van alles achter plakken
# key is persoon+item
# praktisch betekent dit dat de combinatie persoon+item maar 1 keer in deze tabel voor kan komen
# rij:
# observatie: persoon 14 antwoord G op item I1349
# How data is often stored ------------------------------------------------
library(dexter)
verbAggrData[1:10,1:10]
# assignment (10 minutes):
# transform verbAggrData into a tidy format
# using functions from base R and/or the tidyverse packages
# follow up question:
# what would in this case be the difference between the relational and the tidy format?
# Relational data ---------------------------------------------------------
# 1 fact, 1 place, 1 time
# keys and relational constraints
# further reading: Joe Celko; SQL for smarties; chap. 1-3
# The verbal Aggression data consists of a single test form
# In dexter it works like this
db = start_new_project(verbAggrRules,
db_name = ':memory:',
person_properties = list(gender='unknown', anger=as.integer(NA)))
add_booklet(db, verbAggrData, 'VA questionnaire')
# stel je hebt al long format data:
# add_response_data voegt data in tidy format toe
# What does the dexter db look like?
er_plot(db)
# To which table would you add:
# the text of an item?
# response time?
# think of any variables that could be added to each of the other tables
# To extract tidy data from this relational model, use
?get_responses
# many booklets -----------------------------------------------------------
# Educational datasets often consist of many overlapping booklets, i.e. an incomplete design
# typical data
# this is called "compressed format"
# 45098 5098 F 2 D2 4 4 5 6 18 18 16 96 16 96|101100101000000100001100000
# 45099 5099 F 2 D2 4 4 5 6 20 16 16 96 16 96|101100101000000110001100000
# 45102 5102 M 1 D2 4 4 5 6 14 12 16 96 16 96|100000000110110010000000010
# 45103 5103 F 2 D2 4 4 5 6 21 15 16 96 16 96|110100101010000100110000110
# 45236 5236 M 1 D2 4 4 5 6 26 29 16 96 16 96|100111110000011110111100110
# 10697 697 - 3 D2 1 3 0 10 0 21 3 3 97 97|000000000000000000000000000
# 15084 5084 M 1 D2 1 1 0 4 0 26 1 1 97 97|000000000000000000000000000
# 20143 143 F 2 D2 2 2 5 6 37 0 6 86 98 98|100011011111110011111010101
# 20432 432 M 1 D2 2 1 0 4 2 0 5 5 98 98|000011000000000000000000000
# 22515 2515 M 1 D2 2 1 5 6 11 0 5 85 98 98|000011001010000010010100000
# 22880 2880 F 2 D2 2 2 0 8 7 0 6 6 98 98|011010010010000000000000000
# ^ ^ ^ responses ^
# probably person id |
# probably booklet id
# What are the strengths and weaknesses of this dataformat?
# What would you need to do to transform this to a tidy format?
# 1. maak er een data.frame van met individuele antwoorden in kolommen
# 2. documenteer je aannames
# 3. scheid persoonskenmerken en data
# 4. naar long format
# probleem: geen item identificatie
# vergeleken met het eerdere voorbeeld heb je hier een incompleet design
# bij dit soort bestanden heb je vaak een design bestand -> welke items in welk boekje
# boekje 97: lijst met item id's in de volgorde van afname
# dus: maak item positie kolom aan om te joinen met het design
# other common format is the extended format
# e.g. R packages TAM and mirt
# Opdracht: Data van het vergelijkingsonderzoek referentiesets Lezen
# Op http://www.toetsspecials.nl/html/referentiesets_openbaar/taal.shtm
# staat de data voor het vergelijkingsonderzoek referentiesets lezen.
# Deze is redelijk beroerd.
# Aan jullie de taak om deze dataset om te zetten in een vorm waar je een analyse mee kan doen.
# a) bewerk de data en zet deze in een dexter database.
# b) Evalueer de uiteindelijke kwaliteit van de data. Bijv.
# - Heb je alle fouten er uit gehaald?
# - Hoe schat je de kans in dat er nog fouten in zitten die je niet hebt gevonden?
# - Zo ja, waar zullen die zitten? Zijn ze in principe wel of niet te achterhalen?
# handmatige databewerking is verboden
# Aanwijzingen:
# Werk samen, verdeel zo mogelijk het werk maar zorg dat je alle aspecten meekrijgt
# Je eindproduct bevat zowel code, commentaar en conclusies. Maak deze in Rmarkdown maar
# begin met scripts
# Data:
# Lees zorgvuldig de toelichting op http://www.toetsspecials.nl/html/referentiesets_openbaar/taal.shtm
# De dataset is onderverdeeld per populatie maar het betreft één enkele verbonden dataset, je dient
# deze dus te combineren.
# Ga er nooit zomaar vanuit dat data kloppen zonder dat te controleren. Controleer met name
# of identificaties (persoon, item, boekje) wel uniek zijn en of hetzelfde item-antwoord altijd gelijk
# wordt gescoord
# De csv bestanden zijn gedeeltelijk onjuist opgeslagen. Voor het downloaden van de bestanden en het inlezen
# in een data.frame heb ik hieronder een script en functie beschikbaar gesteld.
# Er zijn 3 soorten bestanden: extended, design en antwoorden. Je hebt ze allemaal nodig. Design heeft op elke
# regel in de eerste kolom het boekjesnummer (boekjes identificatie) gevolgd door de id's van de items in dat boekje.
library(xml2)
library(dplyr)
library(tidyr)
library(stringr)
library(stringi)
# data waar:
url = 'http://www.toetsspecials.nl/html/referentiesets_openbaar/taal.shtm'
doc = read_html(url)
# het is leesvaardigheid maar wordt taal genoemd
filenames = xml_find_all(doc, "//a[contains(@href,'csv') ]/@href") %>%
xml_text() %>%
paste0('http://www.toetsspecials.nl', .)
# dit zijn de bestanden die je hebt
filenames
# functie om de csv's te lezen
# see ?read.csv2 for the ... arguments
read_messy_csv = function(file_url, ...)
{
tmp = tempfile(fileext='.csv')
download.file(url=file_url, destfile=tmp)
# het probleem is missende cellen aan het eind van de rijen
# gelukkig zijn er geen strings met quotes, dus deze simpele fix werkt
l = readLines(tmp)
sp = str_count(l,';')
ncol = max(sp)
l = paste0(l, sapply(ncol-sp, function(x) paste0(rep(';',x), collapse='')))
writeLines(l,tmp)
read.csv2(tmp, ...)
}
# test functie
filenames[1]
df1 = read_messy_csv(filenames[1])
filenames[2]
df2 = read_messy_csv(filenames[2], header=F)
filenames[3]
df3 = read_messy_csv(filenames[3], header=F)
# second lecture ----------------------------------------------------------
# coding
# assume data.frame handling (dplyr, tidyr) is known:
# maybe some lacunes, we'll discuss
# 1) abstraction
# 2) regular expressions
# 3) working with lists
# then work through assignment
# Regular expression basics
# I gebruik altijd:
# basic reference:
# https://www.w3schools.com/jsref/jsref_obj_regexp.asp
# reminder lookahead, lookbehind:
# https://www.regular-expressions.info/lookaround.html
# In R
# double \\ in string
# matching
grepl('^\\d{4}[A-Z]{2}$','457TD',perl=TRUE)
# replacement
gsub('\\d{4}[A-Z]{2}','postcode', 'dit is een 6457TD denk ik',perl=TRUE)
# extraction
library(stringr)
str_extract('dit is een 6457TD denk ik die ik eruit wil','\\d{4}[A-Z]{2}')
# working with lists
# goal (usually) getting to data.frame ready data
# common pattern:
lapply(lst, function(elem) { }) |> bind_rows()
# zelfde voor een named list (bijv. de listnames zijn schooltypes) waar schooltype een niuewe kolom moet worden
lapply(lst, function(elem) { }) |> bind_rows(.id='schooltype')
# other common patterns
# getting information about (list) elements within lists in a vector
# usually an intermediate step in getting to a dataframe
# e.g. length of vectors in a list
elem_length = sapply(lst, length)
# now make one data.frame with some element specific infromation added, e.g.
tibble(name = rep(names(lst),elem_length), content = unlist(lst))
# apply (over columns or rows of a matrix or data.frame), get a list, one element per row or column in the original
# rows
apply(x,1,function(row){ }, simplify=FALSE)
# columns
apply(x,2,function(col){ }, simplify=FALSE)