Estoy tratando de agregar una columna a mi conjunto de datos existente. El conjunto de datos tiene tres columnas:

  • Student (que es la columna con la ID del participante),
  • Week (el número de la semana del año durante el cual se recopilaron los datos), y
  • Day (el número del día de la semana durante el cual los datos fueron recogido).

Ahora, una nueva columna Obs que estoy tratando de crear contendría un número progresivo (de 1 a n) que se refiere a la semana durante la cual se evaluó a cada estudiante.

He intentado usar group_by en combinación con rep pero no parece producir el resultado que quiero:

Week <- c(1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4)
Day <- c(1, 2, 3, 2, 3, 5, 1, 3, 2, 3, 4, 5)
Student <- c("A", "A", "A", "B", "B", "B", "B", "B", "C", "C", "C", "C")
fake.db <- data.frame(Student, Week, Day)

library(dplyr)
fake.db %>%
  group_by(Student) %>% 
  mutate(Obs = rep(1:length(Student), each = Week))
#   Student  Week   Day   Obs
#   <fct>   <dbl> <dbl> <int>
# 1 A           1     1     1
# 2 A           1     2     2
# 3 A           1     3     3
# 4 B           2     2     1
# 5 B           2     3     2
# 6 B           2     5     3
# 7 B           3     1     4
# 8 B           3     3     5
# 9 C           4     2     1
#10 C           4     3     2
#11 C           4     4     3
#12 C           4     5     4

Lo que me gustaría obtener es diferente. Para la primera semana de recopilación de datos, se debe informar 1, y para los estudiantes para quienes se recopilaron datos durante una segunda semana, se debe informar 2, etc.

#   Student Week Day Obs
#1        A    1   1   1
#2        A    1   2   1
#3        A    1   3   1
#4        B    2   2   1
#5        B    2   3   1
#6        B    2   5   1
#7        B    3   1   2
#8        B    3   3   2
#9        C    4   2   1
#10       C    4   3   1
#11       C    4   4   1
#12       C    4   5   1
1
Michael Matta 10 may. 2019 a las 23:30

4 respuestas

La mejor respuesta

Una posibilidad dplyr podría ser:

fake.db %>%
 group_by(Student) %>%
 mutate(Obs = cumsum(!duplicated(Week)))

  Student  Week   Day   Obs
   <fct>   <dbl> <dbl> <int>
 1 A           1     1     1
 2 A           1     2     1
 3 A           1     3     1
 4 B           2     2     1
 5 B           2     3     1
 6 B           2     5     1
 7 B           3     1     2
 8 B           3     3     2
 9 C           4     2     1
10 C           4     3     1
11 C           4     4     1
12 C           4     5     1

Se agrupa por columna "Estudiante" y calcula la suma acumulativa de valores "Semana" no duplicados.

O:

fake.db %>%
 group_by(Student) %>%
 mutate(Obs = with(rle(Week), rep(seq_along(lengths), lengths)))

Se agrupa por columna "Estudiante" y crea un ID de grupo de tipo de longitud de ejecución alrededor de la columna "Semana".

O:

fake.db %>%
 group_by(Student) %>%
 mutate(Obs = dense_rank(Week))

Se agrupa por columna "Estudiante" y clasifica los valores en la columna "Semana".

4
tmfmnk 10 may. 2019 a las 20:42

Lo que entiendo es que quieres contar las semanas desde la primera semana de exámenes para cada estudiante. Es decir. La semana 2 es la primera semana de pruebas del estudiante B, por lo que obtiene Obs = 1. Eso significa que puede hacer una mutación agrupada:

library(dplyr)
fake.db <- structure(list(Student = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L), .Label = c("A", "B", "C"), class = "factor"), Week = c(1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4), Day = c(1, 2, 3, 2, 3, 5, 1, 3, 2, 3, 4, 5)), class = "data.frame", row.names = c(NA, -12L))
fake.db %>%
  group_by(Student) %>%
  mutate(Obs = Week - min(Week) + 1)
#> # A tibble: 12 x 4
#> # Groups:   Student [3]
#>    Student  Week   Day   Obs
#>    <fct>   <dbl> <dbl> <dbl>
#>  1 A           1     1     1
#>  2 A           1     2     1
#>  3 A           1     3     1
#>  4 B           2     2     1
#>  5 B           2     3     1
#>  6 B           2     5     1
#>  7 B           3     1     2
#>  8 B           3     3     2
#>  9 C           4     2     1
#> 10 C           4     3     1
#> 11 C           4     4     1
#> 12 C           4     5     1

Creado el 10/05/2019 por el paquete reprex (v0.2.1)

2
Calum You 10 may. 2019 a las 20:35

Un breve método con by

unlist(by(fake.db, fake.db[, 1], function(x) as.numeric(factor(x[, 2]))))
# A1 A2 A3 B1 B2 B3 B4 B5 C1 C2 C3 C4 
#  1  1  1  1  1  1  2  2  1  1  1  1

Datos

fake.db <- structure(list(Student = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 
2L, 2L, 3L, 3L, 3L, 3L), .Label = c("A", "B", "C"), class = "factor"), 
    Week = c(1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 4), Day = c(1, 
    2, 3, 2, 3, 5, 1, 3, 2, 3, 4, 5)), class = "data.frame", row.names = c(NA, 
-12L))
2
jay.sf 10 may. 2019 a las 22:17

Puedes ver si hay una diferencia distinta de cero

fake.db %>%
  group_by(Student) %>% 
  arrange(Week) %>%
  mutate(Obs = cumsum(c(1, diff(Week)!=0)))

O si sus valores no son numéricos, puede compararlos con el valor de retraso

fake.db %>%
  group_by(Student) %>% 
  arrange(Week) %>%
  mutate(Obs = cumsum(Week != lag(Week, default=first(Week))) + 1)
1
MrFlick 10 may. 2019 a las 20:38