У меня есть пример, в котором я хочу создать столбец m, где если x1, x2 или x3 = «A» или «B», то m = 1, иначе m = 0.
df <- data.frame(x1 = LETTERS[1:10], x2 = LETTERS[2:11], x3 = LETTERS[3:12])
df <- df%>%
mutate(m = ifelse(df[,paste0("x",1:3)] %in% c("A","B") ,1,0))
при использовании этого кода он не работает, и я не знаю, где ошибка и как ее исправить. Спасибо.
Спасибо. и, если быть точным, мне нужны только эти три столбца (в случае, если у меня больший фрейм данных, но я хочу использовать только эти три столбца)?
Я бы предложил использовать функцию case_when вместо ifelse. Затем вы можете указать оператор x %in% c('A', 'B') ~ 1 для всех переменных от x1 до x3, а затем использовать .default = 0, чтобы установить значение в ноль, в противном случае
Спасибо. не могли бы вы написать код с помощью case_when, поскольку я никогда раньше не использовал эту функцию
я пробовал использовать case_when, но у меня та же проблема при использовании %in%. Это не работает
df %>% rowwise() %>% mutate(m = case_when(any(c(x1,x2,x3) %in% c("A","B"))~1, .default=0))Теперь у меня другая проблема: у меня так много столбцов, а вместо x1,x2,x3 я хочу использовать Paste0, но с этим кодом он не работает. как справиться с этим с помощью Paste0?





Вы можете использовать rowSums. Лучше используйте grep вместо paste подхода.
> df |>
+ transform(m=+(rowSums(sapply(df[grep('^x\\d$', names(df))], `%in%`, c('A', 'B'))) > 0))
x1 x2 x3 m
1 A B C 1
2 B C D 1
3 C D E 0
4 D E F 0
5 E F G 0
6 F G H 0
7 G H I 0
8 H I J 0
9 I J K 0
10 J K L 0
dplyr::mutate тоже должно работать, не устанавливал. По возможности избегайте ifelse и тому подобного, это просто медленно.
Иногда вы можете воспользоваться особой структурой ваших данных. Если вы ищете A и B только среди заглавных букв A-Z, вы можете сделать:
cols <- c("x1", "x2", "x3")
df$m <- as.integer(do.call(pmin, df[cols]) < "C")
x1 x2 x3 m
1 A B C 1
2 B C D 1
3 C D E 0
4 D E F 0
5 E F G 0
6 F G H 0
7 G H I 0
8 H I J 0
9 I J K 0
10 J K L 0
Не нужно проверять по строкам, вы можете попробовать
df$m <- +(rowMeans(`dim<-`(as.matrix(df) %in% c("A", "B"), dim(df))) > 0)
или
df$m <- +(rowMeans(`dim<-`(unlist(df, FALSE, FALSE) %in% c("A", "B"), dim(df))) > 0)
и вы получите
> df
x1 x2 x3 m
1 A B C 1
2 B C D 1
3 C D E 0
4 D E F 0
5 E F G 0
6 F G H 0
7 G H I 0
8 H I J 0
9 I J K 0
10 J K L 0
Разве unlist() не будет намного быстрее, чем as.matrix()?
да, это быстрее @s_baldur
Для тех из нас, кто забыл :-), стоит отметить, что +(stuff) преобразует логические значения в числовые.
Вот вариант purrr::map (три варианта) с помощниками выбора, чтобы вы могли иметь больше столбцов со сложными именами:
library(tidyverse)
# Toy data
df <- data.frame(x1 = LETTERS[1:10], x2 = LETTERS[2:11], x3 = LETTERS[3:12])
# Just helpers
aux <- c("A", "B")
fn <- \(x, y) any(x %in% y)
# Option 1 A `pmap`
df$m <- pmap_int(
select(df, starts_with("x")),
\(...) some(list(...), \(x) fn(aux, x)))
# Option 2 `mutate` and `pmap`
df <- df %>%
mutate(n = pmap_int(
select(., starts_with("x")),
\(...) some(list(...), \(x) fn(aux, x))))
# Option 3: rowwise, `mutate` and `map`
df <- df %>%
rowwise() %>%
mutate(o = map_int(
list(c_across(starts_with("x"))),
\(x) fn(aux, x))) %>%
ungroup() # Always ungroup it after a `rowwise` operation
Выход:
> df
# A tibble: 10 × 6
x1 x2 x3 m n o
<chr> <chr> <chr> <int> <int> <int>
1 A B C 1 1 1
2 B C D 1 1 1
3 C D E 0 0 0
4 D E F 0 0 0
5 E F G 0 0 0
6 F G H 0 0 0
7 G H I 0 0 0
8 H I J 0 0 0
9 I J K 0 0 0
10 J K L 0 0 0
Created on 2024-05-17 with reprex v2.1.0
%in%в данном случае не будет работать, если вы не примените функцию к каждому столбцу:sapply(df, \(x) +x %in% c("A","B"))