r #if-statement #conditional-statements
#r #оператор if #условные операторы
Вопрос:
Предположим, у меня есть следующий фрейм данных:
x <- c(1, 1, 2, 3, 4, 5)
y <- c(1, 1, 1, 3, 4, 5)
z <- c(NA, 1, 1, 3, 4, NA)
чтобы получить:
x y z
1 1 NA
1 1 1
2 1 1
3 3 3
4 4 4
5 4 NA
и я хотел получить условный оператор таким образом, что если все значения x, y и z, отличные от NA, равны 1, то они будут помечены как 1, как мне приступить к написанию этого сценария?
Например, я хочу следующее:
x y z flag1
1 1 NA 1
1 1 1 1
2 1 1 0
3 3 3 0
4 4 4 0
5 4 NA 0
Кроме того, я также хотел бы указать, содержит ли какая-либо из переменных 4, игнорируя NA, чтобы я мог получить:
x y z flag1 flag2
1 1 NA 1 0
1 1 1 1 0
2 1 1 0 0
3 3 3 0 0
4 4 4 0 1
5 4 NA 0 1
Ответ №1:
Проще всего с rowSums
df$flag <- (!rowSums(df != 1, na.rm = TRUE) amp; !!rowSums(!is.na(df)))
df$flag2 <- (rowSums(df == 4, na.rm = TRUE) > 0 amp; !!rowSums(!is.na(df)))
-вывод
> df
x y z flag flag2
1 1 1 NA 1 0
2 1 1 1 1 0
3 2 1 1 0 0
4 3 3 3 0 0
5 4 4 4 0 1
6 5 4 NA 0 1
In tidyverse
, мы можем использовать if_all
with if_any
для создания этих столбцов
library(dplyr)
df %>%
mutate(flag1 = (if_all(everything(), ~is.na(.)| . %in% 1)),
flag2 = (if_any(x:z, ~ . %in% 4)))
x y z flag1 flag2
1 1 1 NA 1 0
2 1 1 1 1 0
3 2 1 1 0 0
4 3 3 3 0 0
5 4 4 4 0 1
6 5 4 NA 0 1
данные
df <-structure(list(x = c(1, 1, 2, 3, 4, 5), y = c(1, 1, 1, 3, 4,
4), z = c(NA, 1, 1, 3, 4, NA)), class = "data.frame", row.names = c(NA,
-6L))
Комментарии:
1. Когда я запускаю этот аналогичный код в своем фактическом наборе данных, в котором есть наблюдения со всеми NA, он помечается как «1». Есть ли способ игнорировать наблюдения, где все это NA?
2. @ssjjaca я думал об этом. Раньше я думал, что это не так. Вы можете либо добавить условие с
is.na
помощью (как в обновлении), либо пропустить эти строки в вычислении с помощьюis.na
Ответ №2:
Вот версия, которая более подробная, чем ответ @Akrun (и медленнее для больших наборов данных), но более настраиваемая:
flag1 <- ifelse( (x == 1 | is.na(x) ) amp;
(y == 1 | is.na(y) ) amp;
(z == 1 | is.na(z) ), 1, 0)
flag2 <- ifelse( x == 4 | y == 4 | z == 4, 1, 0)
Если бы у вас была куча этих векторов, вы могли бы сохранить их в matrix или data.frame, поэтому вам не нужно перечислять каждый столбец для выполнения вычисления:
mat <- cbind(x,y,z)
flag1 <- apply(mat, 1, function(r) sum(r==1 | is.na(r)) == length(r))
flag2 <- apply(mat, 1, function(r) any(r==4, na.rm=T))
Ответ №3:
Использование функции apply:
apply(df, 1, function(x) all(x == 1,na.rm = 1))
[1] 1 1 0 0 0 0
apply(df, 1, function(x) any(x == 4,na.rm = 1))
[1] 0 0 0 0 1 0
Используемые данные:
df
x y z
1 1 1 NA
2 1 1 1
3 2 1 1
4 3 3 3
5 4 4 4
6 5 5 NA
Ответ №4:
Вот дополнительный альтернативный способ поворота с использованием all
и any
:
library(tidyr)
library(dplyr)
df %>%
pivot_longer(
cols=everything()
) %>%
mutate(id = as.integer(gl(n(), 3, n()))) %>%
group_by(id) %>%
mutate(flag1 = ifelse(all(value == 1, na.rm=TRUE), 1,0),
flag2 = ifelse(any(value == 4, na.rm=TRUE), 1,0)) %>%
pivot_wider(
names_from = name,
values_from = value
) %>%
ungroup() %>%
select(x,y,z,flag1, flag2)
вывод:
x y z flag1 flag2
<dbl> <dbl> <dbl> <dbl> <dbl>
1 1 1 NA 1 0
2 1 1 1 1 0
3 2 1 1 0 0
4 3 3 3 0 0
5 4 4 4 0 1
6 5 4 NA 0 1
Ответ №5:
library(tidyverse)
df = tibble(
x = c(1, 1, 2, 3, 4, 5),
y = c(1, 1, 1, 3, 4, 5),
z = c(NA, 1, 1, 3, 4, NA)
)
df %>% mutate(
flag1 = ifelse((x==1 | is.na(x)) amp; (y==1 | is.na(y)) amp; (z==1 | is.na(z)), 1, 0),
flaf2 = ifelse((x==4 | is.na(x)) | (y==4 | is.na(y)) | (z==4 | is.na(z)), 1, 0)
)
вывод
# A tibble: 6 x 5
x y z flag1 flaf2
<dbl> <dbl> <dbl> <dbl> <dbl>
1 1 1 NA 1 1
2 1 1 1 1 0
3 2 1 1 0 0
4 3 3 3 0 0
5 4 4 4 0 1
6 5 5 NA 0 1
Обновление 1
Обратите внимание, вы не можете забыть решить, что делать, когда все переменные NA
. Вот исправленная версия одного из возможных решений.
library(tidyverse)
df = tibble(
x = c(1, 1, 2, 3, 4, 5, NA),
y = c(1, 1, 1, 3, 4, 5, NA),
z = c(NA, 1, 1, 3, 4, NA, NA)
)
df %>% mutate(
flag1 = ifelse(is.na(x) amp; is.na(y) amp; is.na(z), NA,
ifelse((x==1 | is.na(x)) amp; (y==1 | is.na(y)) amp; (z==1 | is.na(z)), 1, 0)),
flag2 = ifelse(is.na(x) amp; is.na(y) amp; is.na(z), NA,
ifelse((x==4 | is.na(x)) | (y==4 | is.na(y)) | (z==4 | is.na(z)), 1, 0))
)
вывод
# A tibble: 7 x 5
x y z flag1 flag2
<dbl> <dbl> <dbl> <dbl> <dbl>
1 1 1 NA 1 1
2 1 1 1 1 0
3 2 1 1 0 0
4 3 3 3 0 0
5 4 4 4 0 1
6 5 5 NA 0 1
7 NA NA NA NA NA
Ответ №6:
Вот вариант, использующий rowwise
и c_across
:
library(dplyr)
df %>%
rowwise() %>%
mutate(flag1 = as.numeric(all(c_across() == 1, na.rm = T)),
flag2 = as.numeric(any(c_across() == 4, na.rm = T))) %>%
ungroup()
c_across
объединит каждую строку в атомарный вектор для сравнения с вашим условием.
Примечание: по умолчанию c_across
работает во всех столбцах. Вы можете изменить это с помощью любого синтаксиса tidyselect. Например, x:z
.
x y z flag1 flag2
<dbl> <dbl> <dbl> <dbl> <dbl>
1 1 1 NA 1 0
2 1 1 1 1 0
3 2 1 1 0 0
4 3 3 3 0 0
5 4 4 4 0 1
6 5 4 NA 0 1