Skip to content

Instantly share code, notes, and snippets.

@branning
Last active August 29, 2015 14:22
Show Gist options
  • Select an option

  • Save branning/8dec2077b89ed477da89 to your computer and use it in GitHub Desktop.

Select an option

Save branning/8dec2077b89ed477da89 to your computer and use it in GitHub Desktop.
# open https://docs.google.com/spreadsheets/d/1k77hjQolIU3Lw6mq-d1GgbKQQpTPU6obExG5CsfI4E0
# highlight whole column, Ctrl+C
import json
src = '''
0.1833333333
0.4333333333
0.45
0.45
0.5166666667
0.55
0.6
0.6333333333
0.65
0.6666666667
0.6833333333
0.6833333333
0.7166666667
0.7666666667
0.8
0.8166666667
0.85
0.8833333333
0.8833333333
0.9
0.9333333333
0.95
0.95
0.9666666667
0.9833333333
1
1.066666667
1.116666667
1.116666667
1.166666667
1.183333333
1.216666667
1.216666667
1.266666667
1.316666667
1.316666667
1.366666667
1.383333333
1.433333333
1.633333333
1.633333333
1.7
1.716666667
1.833333333
1.9
1.916666667
1.95
2.033333333
2.033333333
2.066666667
2.1
2.266666667
2.333333333
2.366666667
2.366666667
2.5
2.533333333
2.566666667
2.65
2.666666667
2.683333333
3.133333333
3.25
3.266666667
3.633333333
3.733333333
4.15
4.266666667
4.35
4.383333333
4.783333333
4.866666667
4.95
5
5
5.066666667
5.066666667
5.066666667
5.066666667
5.133333333
5.133333333
5.216666667
5.233333333
5.35
5.366666667
5.433333333
5.583333333
5.666666667
5.666666667
5.75
5.883333333
6.033333333
6.166666667
6.183333333
6.233333333
6.25
6.266666667
6.266666667
6.466666667
6.483333333
6.516666667
6.733333333
6.75
6.9
6.916666667
7.016666667
7.216666667
7.233333333
7.25
7.35
7.533333333
7.533333333
7.533333333
7.716666667
7.783333333
7.916666667
7.916666667
8
8.05
8.05
8.15
8.166666667
8.2
8.2
8.25
8.333333333
8.466666667
8.483333333
8.5
8.533333333
8.566666667
8.633333333
8.633333333
8.733333333
8.733333333
8.816666667
8.95
8.966666667
9.016666667
9.05
9.066666667
9.1
9.1
9.2
9.266666667
9.316666667
9.366666667
9.4
9.483333333
9.516666667
9.533333333
9.55
9.583333333
9.583333333
9.6
9.6
9.633333333
9.65
9.733333333
9.933333333
9.966666667
9.983333333
9.983333333
10.15
10.15
10.16666667
10.2
10.21666667
10.23333333
10.23333333
10.25
10.3
10.38333333
10.53333333
10.53333333
10.78333333
10.85
10.88333333
10.98333333
11.03333333
11.06666667
11.08333333
11.15
11.21666667
11.21666667
11.35
11.35
11.36666667
11.36666667
11.38333333
11.45
11.53333333
11.63333333
11.66666667
11.96666667
12.03333333
12.1
12.11666667
12.2
12.23333333
12.38333333
12.38333333
12.56666667
12.7
12.73333333
12.78333333
12.83333333
13
13.06666667
13.25
13.28333333
13.31666667
13.31666667
13.36666667
13.4
13.4
13.4
13.53333333
13.6
13.8
13.96666667
14.01666667
14.11666667
14.21666667
14.21666667
14.23333333
14.23333333
14.36666667
14.36666667
14.41666667
14.45
14.61666667
14.65
14.68333333
15.1
15.2
15.21666667
15.38333333
15.68333333
15.68333333
15.71666667
15.73333333
15.78333333
16.15
16.25
16.45
16.65
16.9
16.93333333
17.23333333
17.23333333
17.73333333
17.95
17.96666667
18
18.33333333
18.38333333
18.46666667
18.48333333
18.58333333
18.78333333
18.9
19
19.13333333
19.18333333
19.25
19.4
19.66666667
20.26666667
20.46666667
20.55
20.58333333
20.73333333
21.56666667
21.65
21.83333333
21.88333333
22.06666667
22.56666667
22.61666667
22.63333333
23.51666667
24
24.23333333
24.28333333
24.48333333
24.73333333
24.86666667
25.2
25.23333333
25.58333333
25.76666667
26.35
26.85
27.06666667
27.91666667
28
28.5
28.78333333
30.58333333
31.15
31.26666667
31.55
31.86666667
33.31666667
33.8
33.91666667
33.98333333
35.21666667
35.6
35.95
36.16666667
37.28333333
38.45
38.63333333
38.73333333
39.18333333
39.93333333
41.76666667
42.9
43.2
44.51666667
45.93333333
46.78333333
50.21666667
51.85
54.13333333
55.46666667
58.66666667
66.56666667
78.48333333
81.91666667
82.9
97.78333333
109.9833333
110.5
122.5333333
131.7166667
142.1333333
146.9166667
151.9333333
176.8166667
181.4833333
204.3666667
208.1666667
212.9833333
221
221.2333333
242.1833333
251.5
317.8333333
322.0833333
344.7333333
373.3333333
374.6
482.65
549.6166667
560.5
577.1
627.55
653.3333333
689.6
759.4
776.0666667
787.3666667
808.1833333
848.65
854.3166667
959.4333333
1002.35
1018.483333
1143.333333
1151.783333
1153.333333
1159.866667
1210.65
1261.85
1306.166667
1327.683333
1328.666667
1330.75
1332.266667
1369.1
1380.75
1479.466667
1483.2
1583.566667
1588.633333
1591.016667
1783.133333
1803.05
1811.666667
1882.816667
1984.15
2075.1
2166.883333
2184.9
2359.783333
2606.85
2740.6
2761.8
2803.116667
2872.683333
2926.383333
3073.033333
3102.316667
3146.383333
3156.416667
3362.9
3365.883333
3380.983333
3413.116667
3821.783333
4110.85
4154.516667
4262.283333
4271.933333
4478.6
4692.733333
5485.7
5611.833333
5788.816667
31103.05
'''
minutes = map(float, src.split())
with open('minutes.json', 'w') as fn:
json.dump(fn, minutes)
---
output: html_document
---
```{r include=FALSE}
# install.packages(jsonlite)
# install.packages(mixtools)
# install.packages(vioplot)
```
How much time was spent doing the problem?
------
Load the data we prepared in Python
```{r message=FALSE}
library(jsonlite)
minutes <- fromJSON('minutes.json')
```
We'd like this data to be normally distributed so we can simply take the mean and go home. Let's take a look at at the shape of the data to see if that's a reasonable thing to do. First, let's visualize normality with a Q-Q plot. We hope the data lies along the line.
```{r}
qqnorm(minutes)
qqline(minutes)
```
Whoa! What a mess. That last data point is so far outside of the others that it may be a data input error. Let's drop it, and try again.
```{r}
minutes <- head(minutes, -1)
qqnorm(minutes)
qqline(minutes)
```
Still no good. Let's assume our numbers represent a mixture of two data sources. Some people aren't so diligent, and leave their homework open while they walk the dog, go to sleep, or apparently take a 3-week vacation. Diligent students close the assignment when complete, and move on to the next exercise. The times are a mix of diligent and less diligent students, so we model them as a mixture of 2 normal distributions with `normalmixEM` from the CRAN package `mixtools`. From this we get a posterior likelihood of membership of each category for each measured duration.
Fit the 2-source normal mixture model.
```{r message=FALSE}
library(mixtools)
mixtimes <- normalmixEM(minutes)
```
```{r}
summary(mixtimes)
plot(mixtimes,which=2)
lines(density(minutes),lty=2,lwd=2)
```
```{r message=FALSE}
library(vioplot)
```
Component 1 has average duration `r mixtimes$mu[1]` minutes, and component 2 is `r mixtimes$mu[2]` minutes. We're interested in the measurements that are more likely to be a member of the first component, which has a reasonable duration and therefore probably includes students who actually worked on the problem. Let's see what that group looks like.
```{r}
working <- minutes[mixtimes$posterior[,1] > mixtimes$posterior[,2]]
qqnorm(working)
qqline(working)
vioplot(working)
```
Add up the times that are more likely to be in the first normal distribution, which has lower average duration.
```{r}
mean(working)
```
Students who probably completed the problem took `r mixtimes$mu[1]` minutes to finish.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment