У меня есть данные, сгруппированные по 'student_id':
my_data = data.frame(student_id = c(1,1,1,1,1,2,2,2,2,2,3,3,3,3,3),
exam_no = c(1,2,3,4,5,1,2,3,4,5,1,2,3,4,5),
result = rnorm(15,60,10))
my_data
student_id exam_no result
1 1 1 56.60374
2 1 2 55.76655
3 1 3 53.81728
4 1 4 74.82202
5 1 5 34.91834
6 2 1 58.32422
7 2 2 60.38213
8 2 3 49.40390
9 2 4 63.85426
10 2 5 40.32912
11 3 1 69.54969
12 3 2 43.36639
13 3 3 37.97265
14 3 4 52.36436
15 3 5 61.62080
Мой вопрос:
Для каждого ученика я хочу выбрать набор последовательных строк со случайными начальными и конечными строками.
Например, сохранить экзамены 2–4 для учащегося 1, сохранить экзамены 2–5 для учащегося 2 и т. д.
Я подумал о следующем способе сделать это:
Создайте фрейм данных, содержащий максимальное количество экзаменов, которые сдает каждый студент (в моей задаче каждый студент сдает одинаковое количество экзаменов, но в будущем это может быть иначе)
library(dplyr)
counts = my_data %>% group_by(student_id) %>% summarise(counts = n())
# create variables that indicate where to start ("min") and where to end ("max") for each student
counts$min = sample(1:counts$counts, 1)
counts$max = sample(counts$min:counts$counts,1)
Отсюда я собирался написать цикл, который выбирал бы строки между «минимальным» и «максимальным» индексом для каждого ученика (например, my_data[min:max]), но результаты предыдущего кода дают мне предупреждения и нелогично Результаты:
Warning message:
In 1:counts$counts :
numerical expression has 3 elements: only the first used
Warning messages:
1: In counts$min:counts$counts :
numerical expression has 3 elements: only the first used
2: In counts$min:counts$counts :
numerical expression has 3 elements: only the first used
# A tibble: 3 x 4
student_id counts min max
<dbl> <int> <int> <int>
1 1 5 4 5
2 2 5 4 5
3 3 5 4 5
Я не уверен, как продолжить это - может кто-нибудь показать мне, как продолжить?
Спасибо!
В качестве альтернативы вы можете сделать что-то вроде (а) выбора начальной строки, а затем (б) выбрать несколько строк для выборки из этой начальной строки. Это позволит вам легко сделать что-то вроде "выбрать 3, 4 или 5 случайных строк от каждого ученика" - хотя в зависимости от того, насколько вы обеспокоены предвзятостью, он может предпочесть более позднюю строку более ранним...
Связано: выберите две случайные и последовательные строки из сгруппированных данных (отказ от ответственности: я, по-видимому, также ответил на это... ;); выборка n случайно выбранных последовательных строк на всех уровнях фактора, но с фиксированным размером выборки.
Базовый вариант R, использующий cumsum для обозначения промежуточных последовательных строк.
subset(
my_data,
ave(
exam_no,
student_id,
FUN = function(x) cumsum(seq_along(x) %in% sample.int(length(x), 2))
) == 1
)
Что дает, например
student_id exam_no result
2 1 2 61.83643
3 1 3 51.64371
4 1 4 75.95281
6 2 1 51.79532
7 2 2 64.87429
8 2 3 67.38325
11 3 1 75.11781
12 3 2 63.89843
13 3 3 53.78759
Более компактная версия от data.table с той же идеей, что и выше.
library(data.table)
setDT(my_data)[, .SD[cumsum((1:.N) %in% sample.int(.N, 2)) == 1], student_id]
Используя data.table, в каждой группе выберите два значения из .I (без замены) и создайте последовательность индексов.
library(data.table)
setDT(my_data)
set.seed(3)
my_data[my_data[ , {ix = sample(.I, 2); ix[1]:ix[2]}, by = student_id]$V1]
# student_id exam_no result
# <num> <num> <num>
# 1: 1 5 74.05672
# 2: 1 4 49.37525
# 3: 1 3 67.41662
# 4: 1 2 67.64935
# 5: 2 4 55.15337
# 6: 2 3 58.95694
# 7: 3 4 50.79859
# 8: 3 3 53.66886
# 9: 3 2 47.01089
Вам всегда нужно несколько строк на группу? Студент 1 имеет 5 рядов. В вашей попытке, если минимальная строка была 5 для учащегося 1, больше не осталось строк для выборки. Все хорошо? Или вам нужен метод, чтобы получить как минимум 2 строки на ученика? Какое распределение количества строк на одного ученика вы бы хотели? Если мы продолжим ваш метод — случайным образом выберем начальную и конечную строки — вы, как правило, выберете больше строк от студентов с большим количеством данных.