#r #dplyr
Вопрос:
Допустим, у меня есть следующий df
df <- read.table(text = "team id result result_number
A 1 999 999
A 2 cat 45
A 3 dog 50
B 4 999 999
B 5 three 60
B 6 four 30
C 7 999 999
C 8 rabbit 45
C 9 monkey 11
D 10 dog 12
D 11 999 999
D 12 basket 10", header = T)
Для каждой строки, имеющей 999 в result
категории, я хотел бы заменить это значение (и соответствующее result_number
значение) значениями из случайной строки в той же команде (например, случайным образом в пределах A, B, C или D), которое не является 999.
Итак, вот пример вывода:
df <- read.table(text = "team id result result_number
A 1 cat 45
A 2 cat 45
A 3 dog 50
B 4 four 30
B 5 three 60
B 6 four 30
C 7 rabbit 45
C 8 rabbit 45
C 9 monkey 11
D 10 dog 12
D 11 basket 10
D 12 basket 10", header = T)
Я не могу придумать элегантный способ сделать это в dplyr без действительно неуклюжей внешней функции
Ответ №1:
Сгруппированные по «команде», зациклите across
столбцы «результат», «номер результата», replace
, где значение равно 999 с sample
числом элементов, которые не равны ( !=
) 999, и верните одно значение
library(dplyr)
df %>%
group_by(team) %>%
mutate(across(result:result_number,
~ replace(., as.character(.)== "999",
sample(.[as.character(.) != "999"], 1)))) %>%
ungroup
-выход
# A tibble: 12 × 4
team id result result_number
<chr> <int> <chr> <int>
1 A 1 dog 45
2 A 2 cat 45
3 A 3 dog 50
4 B 4 four 30
5 B 5 three 60
6 B 6 four 30
7 C 7 monkey 45
8 C 8 rabbit 45
9 C 9 monkey 11
10 D 10 dog 12
11 D 11 dog 10
12 D 12 basket 10
Комментарии:
1. Просто краткое примечание для OP о сравнении столбца символов
result
с числовым значением999
(например. == 999
, и. != 999
), что значения приводятся к одному и тому же типу в следующем порядке приоритета: символьный, комплексный, числовой, целочисленный, логический и необработанный перед сравнением.2. @LMc да, это правда. Я использовал принуждение в
replace
отличие от того, вcase_when
котором строго для типа3. Спасибо за комментарии. На всякий случай я обновил
as.character
4. @TarJae, потому что вы
sample
используете весь столбец, который также включает 999. Вы можете изменить значениеsample
наsample(.[. != 999], 1, replace = TRUE)
. также имеет значение преобразование типов в комментариях LMc5. Большое спасибо, мастер акрун!!!
Ответ №2:
Этот результат был создан с помощью akrun! Большое спасибо!
library(dplyr)
df %>%
group_by(team) %>%
mutate(across(contains("result"), ~ifelse(.==999, sample(.[. != 999], 1, replace = TRUE),.)))
team id result result_number
<chr> <int> <chr> <int>
1 A 1 cat 50
2 A 2 cat 45
3 A 3 dog 50
4 B 4 four 60
5 B 5 three 60
6 B 6 four 30
7 C 7 monkey 45
8 C 8 rabbit 45
9 C 9 monkey 11
10 D 10 dog 12
11 D 11 dog 12
12 D 12 basket 10