Я пытаюсь найти решение в base
R
, которое может разделить data.frame
на группы на основе значений в столбце (group
), которые также зависят от появления значений в другом столбце (id
).
Например:
У меня есть data.frame
df = data.frame(id = c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,18,18,19,19,20,20),
group = c("A","A","A","A","A","A","A","A","B","B","B","B","C","C","C","C","A","B","A","B","A","B","A","B"),
num = c(0.1,0.1,0.1,0.1,0.2,0.2,0.2,0.2,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1),
value = c(sample(10:90, 16, replace = TRUE), rep(c(21,67,80,69), times=1, each=2)))
> df
id group num value
1 1 A 0.1 59
2 2 A 0.1 72
3 3 A 0.1 82
4 4 A 0.1 17
5 5 A 0.2 39
6 6 A 0.2 46
7 7 A 0.2 39
8 8 A 0.2 56
9 9 B 0.1 31
10 10 B 0.1 46
11 11 B 0.1 63
12 12 B 0.1 15
13 13 C 0.1 51
14 14 C 0.1 68
15 15 C 0.1 48
16 16 C 0.1 28
17 17 A 0.1 21
18 17 B 0.1 21
19 18 A 0.1 67
20 18 B 0.1 67
21 19 A 0.1 80
22 19 B 0.1 80
23 20 A 0.1 69
24 20 B 0.1 69
и я пытаюсь split
data.frame
на основе следующих групп:
> df
$`A`
id group num value
1 1 A 0.1 59
2 2 A 0.1 72
3 3 A 0.1 82
4 4 A 0.1 17
5 5 A 0.2 39
6 6 A 0.2 46
7 7 A 0.2 39
8 8 A 0.2 56
$`B`
id group num value
9 9 B 0.1 31
10 10 B 0.1 46
11 11 B 0.1 63
12 12 B 0.1 15
$`C`
id group num value
13 13 C 0.1 51
14 14 C 0.1 68
15 15 C 0.1 48
16 16 C 0.1 28
$`AB`
id group num value
17 17 A 0.1 21
18 17 B 0.1 21
19 18 A 0.1 67
20 18 B 0.1 67
21 19 A 0.1 80
22 19 B 0.1 80
23 20 A 0.1 69
24 20 B 0.1 69
Последняя группа определяется по парам на основе столбца id
. Это означает, что если id
встречается парами (17,18,19,20), группа считается отдельной группой (AB) по сравнению с группой (A и B), где идентификационная доза не поступает парами (1:12). .
Как этого можно добиться с помощью base
R
? Можно ли это сделать с помощью функции split()
?
Сначала вы можете использовать ave
для создания нужных групп, а затем split
на их основе.
Чтобы последняя группа называлась A + B
, вам нужно свернуть результаты ave
с помощью paste
с помощью +
(или, очевидно, sub
предыдущих результатов toString
). Чтобы разделить его в конце, самый удобный способ, который я могу придумать, — это использовать fct_inorder
в пакете forcats
, в противном случае используйте отличные коды, которыми поделился @Friede, если вы хотите остаться в базе R.
split(df, forcats::fct_inorder(ave(df$group, df$id, FUN = \(x) paste(x, collapse = " + "))))
$A
id group num value
1 1 A 0.1 78
2 2 A 0.1 66
3 3 A 0.1 18
4 4 A 0.1 81
5 5 A 0.2 35
6 6 A 0.2 16
7 7 A 0.2 51
8 8 A 0.2 18
$B
id group num value
9 9 B 0.1 45
10 10 B 0.1 87
11 11 B 0.1 90
12 12 B 0.1 52
$C
id group num value
13 13 C 0.1 85
14 14 C 0.1 24
15 15 C 0.1 41
16 16 C 0.1 16
$`A + B`
id group num value
17 17 A 0.1 21
18 17 B 0.1 21
19 18 A 0.1 67
20 18 B 0.1 67
21 19 A 0.1 80
22 19 B 0.1 80
23 20 A 0.1 69
24 20 B 0.1 69
@benson23 Спасибо! Это сработало. Просто дополнительный вопрос: как я могу изменить метки групп, которые идут парами, т.е. вместо A, B
можно ли будет пометить их как A + B
? Возможно, с FUN = paste
?
@Friede Было бы здорово, если бы порядок сохранился, но я не уверен, последую ли я твоему предложению. Мне нужно будет создать еще одну функцию, чтобы сохранить порядок? Можно ли этого добиться внутри split
или вокруг него, не создавая еще одну функцию?
@SchlaWiener, я бы не предложил это, если бы ваш ожидаемый результат не был в той форме, в которой он находится. Пожалуйста, объясните, что не так с созданием и добавлением в файл функции, полностью написанной на базе R.
@Friede Мне нравится идея сохранения порядка, я определенно предпочел бы иметь это в приведенном выше решении. Я просто не уверен, понимаю ли я, что делает эта функция. x
здесь df
и f
часть ave
? Нет ничего плохого в наличии другой функции. Мне просто было любопытно, есть ли способ добиться этого без добавления новой функции.
Посмотрите в файле помощи. help("split")
. И, конечно, можно было бы написать split(x=df, f=factor(x=f<-ave(df$group, df$id, FUN=toString), unique(f)))
, но это уже продвинуто.
Обновил свой ответ :) @Friede, спасибо за обсуждение!
Спасибо вам обоим @benson23 и @Friede! Ваш вклад очень помог!
Пока пользователь @benson23 не протестует, я хотел бы добавить то, что предложено в комментариях ниже этот ответ.
В базе, без добавления пользовательской функции в среду, сохранение порядка факторов может быть достигнуто следующим образом:
> split(df, factor(f <- ave(df$group, df$id, FUN = \(g) paste(g, collapse = "+")), unique(f)))
$A
id group num value
1 1 A 0.1 54
2 2 A 0.1 81
3 3 A 0.1 40
4 4 A 0.1 15
5 5 A 0.2 35
6 6 A 0.2 22
7 7 A 0.2 83
8 8 A 0.2 69
$B
id group num value
9 9 B 0.1 24
10 10 B 0.1 83
11 11 B 0.1 46
12 12 B 0.1 49
$C
id group num value
13 13 C 0.1 63
14 14 C 0.1 46
15 15 C 0.1 32
16 16 C 0.1 45
$`A+B`
id group num value
17 17 A 0.1 21
18 17 B 0.1 21
19 18 A 0.1 67
20 18 B 0.1 67
21 19 A 0.1 80
22 19 B 0.1 80
23 20 A 0.1 69
24 20 B 0.1 69
и с
split2 = \(x, f, ...) { f = factor(f, levels = unique(f)); split(x, f, ...) }
порядок сохраняется.