Purpose :
Clean, Join & Report Missingness
Define : What is my Data
Demonstrate the ability to interpret Data in Real world Context
Demonstrate the ability to infer the scope of generality of data
Deliverable(s) :
Create Docu. for data
(data_dictionary.csv,README.md)
Create Clean Dat.
(S10_students.csv)
Create Report (S10_Data_Cleaning.Rmd)
Create Codebook (CodeBk.pdf)
Create Loss Diagram (Std_Loss.png)
Explicitly define Sampling Terms :
Element
Population
Sampling Unit
Frame
Sample
Probability Sample
Sampling Design
Meaning :
data_dictionary.csv : Defines each
variable in the final dataset, including its meaning, type, coding,
source, and missingness.
README.md : Summarizes the dataset,
its provenance, structure, limitations, access restrictions, and how to
use the project files.
cohorts.csv : Final cleaned and
de-identified analytic dataset used for analysis.
S10_Data_Cleaning.Rmd :
Reproducible record of how the raw data were cleaned, linked,
anonymized, validated, and converted into
cohorts.csv.
Source(s) of Guidance :
Data Privacy Statement :
Quarter : Fall (F), Winter (W), Spring (S)
Exam : Midterm (M), Final (F)
Version (VA, VB)
For example :
## [1] "First.Name" "Last.Name"
## [3] "SID" "Email"
## [5] "Sections" "Total.Score"
## [7] "Max.Points" "Status"
## [9] "Submission.ID" "Submission.Time"
## [11] "Lateness..H.M.S." "View.Count"
## [13] "Submission.Count" "X1..Question.1..1.0.pts."
## [15] "X2..Question.2..1.0.pts." "X3..Question.3..1.0.pts."
First.Name, Last.Name,
Submission.ID) & indirectly
(Sections, Email). Therefore we are to strip
that information to generate properly anonymized Data.n_rw <-
F_F_VA |> nrow() +
F_F_VB |> nrow() +
W_F_VA |> nrow() +
W_F_VB |> nrow() +
S_F_VA |> nrow() +
S_F_VB |> nrow()
paste0("Sum of all Rows = ", n_rw, " rows")## [1] "Sum of all Rows = 1520 rows"
# Comb. Versions
F_M <-
bind_rows(
F_M_VA |> mutate(version="A", recency = 3),
F_M_VB |> mutate(version="B", recency = 3)
)## [1] "818 rw for Fall Midterm"
## [1] "Therefore 0.54% (most) obs. are from Fall"
First.Name, Last.Name## [1] FALSE
## [1] FALSE
# make all upper
F_M <-
F_M |> mutate(
First.Name = toupper(First.Name),
Last.Name = toupper(Last.Name)
)
# toupper("a")
# rw id
F_M <- F_M |> mutate(rw_idx = row_number()) ## [1] TRUE
## [1] TRUE
First.Name, Last.Name pairs ct## [1] 301
## [1] 818
First.Name, Last.Name
pairs were observed.key_tbl_F_M# add unique std. id. for each unique FL-Name
key_tbl_F_M <-
F_M |>
distinct(First.Name, Last.Name) |>
mutate(std_id = paste0("student_", row_number()))
# Join std_id
F_M <-
F_M |>
left_join(
key_tbl_F_M,
by = c("First.Name", "Last.Name")
)student_110), one 216 times (student_40)student_40## [1] 0.26
Notice some std. are so called UNIDENTIFIED STUDENT
(26%)
All students were graded
These students scores cannot be connected across exams
I suspect these are students whom dropped the course
UNIDENTIFIED STUDENT systematically differ (bias)?# generate binary label
F_M <-
F_M |>
mutate(
dropped = factor(
ifelse(std_id == "student_40", 1, 0),
levels = c(0, 1),
labels = c("Kept", "Dropped")
)
)
# non-ordinal, categorical
F_M$dropped |> unique()## [1] Kept Dropped
## Levels: Kept Dropped
# graph
library(patchwork)
graph_dat <-
F_M |>
filter(Status=="Graded")
# mean, median, mode : based on all dat
mean_pct <- mean(graph_dat$pct)
median_pct <- median(graph_dat$pct)
mode_pct <-
graph_dat$pct |>
na.omit() |>
table() |>
which.max() |>
names() |>
as.numeric()
p1 <-
graph_dat |>
ggplot(aes(
x = pct,
y = after_stat(density),
fill = dropped
)) +
geom_histogram(
position = "identity",
alpha = 0.4
) +
# mean, median, mode
geom_vline(xintercept=mean_pct, linetype="dashed") +
geom_vline(xintercept=median_pct, linetype="dashed") +
geom_vline(xintercept=mode_pct, linetype="dashed")
p2 <-
graph_dat |>
ggplot(aes(
x = pct,
color = dropped
)) +
geom_density(
na.rm = TRUE
) +
# mean, median, mode
geom_vline(xintercept=mean_pct, linetype="dashed") +
geom_vline(xintercept=median_pct, linetype="dashed") +
geom_vline(xintercept=mode_pct, linetype="dashed")
p1 / p2as we can see graphically, our dist appear to come from the same
dist. The density of class student_40 and
non-student_40 ("Kept", "Dropped") appears to
be not systematic.
Looks like both classes ("Kept", "Dropped") maintain
the modality (bimodal)
# summary table
tibble(
Statistic = c("Mean", "Median", "Mode"),
Value = c(mean_pct, median_pct, mode_pct)
)student_110F_M |>
filter(std_id=="student_110") |>
mutate(First.Name = "Person", Last.Name = "Name") |>
select(std_id, First.Name, Last.Name, Status, Total.Score, rw_idx) student_110 has 4 repeated obs. –
where only one is actually graded. We will discard the ungraded
version.Cause <-
F_M[F_M$std_id=="student_110",] |>
distinct(Email, version)
Cause[,]$Email <- rep(c("Email 1", "Email 2"), 2)
Cause; rm(Cause)2 obs. student(s)# v for vector, vector of ct == 2 std_id's
v <- rep_obs_ct[-(1:2),] |> filter(ct == 2) |> pull(std_id)
# rep_obs_ct |> filter(ct == 2) |> nrow() * 2
F_M |> filter(std_id %in% v) |> count(version)here we see of those whom are repeated, half are version A, half version B
VA but not VB could be included for
both although only graded for 1.# ct : (Status, version) pairs
F_M |>
filter(std_id %in% v) |>
count(Status, version) |>
group_by(Status) |>
summarize(ct = sum(n)) |>
mutate(pct = round(ct/sum(ct),2))GradedF_M |>
filter(std_id %in% v) |>
group_by(std_id) |>
summarise(
n_graded = sum(Status == "Graded"),
n_missing = sum(Status == "Missing"),
n_versions = n_distinct(version),
.groups = "drop"
) |>
count(n_graded, n_missing, n_versions)