[英]Ignoring NA in R across multiple columns of Datafrme using na.omit or NA.RM and mapply
[英]R - Applying condition across multiple columns ignoring NA
假設我有以下數據框:
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
我想得到一個條件語句,如果所有非 NA x、y 和 z 值都等於 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
最簡單的是使用rowSums
df$flag <- +(!rowSums(df != 1, na.rm = TRUE) & !!rowSums(!is.na(df)))
df$flag2 <- +(rowSums(df == 4, na.rm = TRUE) > 0 & !!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
在tidyverse
,我們可以使用if_all
和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))
這是一個比@Akrun 的答案更冗長的版本(在更大的數據集上更慢),但更可定制:
flag1 <- ifelse( (x == 1 | is.na(x) ) &
(y == 1 | is.na(y) ) &
(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))
使用應用功能:
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
這是使用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
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)) & (y==1 | is.na(y)) & (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) & is.na(y) & is.na(z), NA,
ifelse((x==1 | is.na(x)) & (y==1 | is.na(y)) & (z==1 | is.na(z)), 1, 0)),
flag2 = ifelse(is.na(x) & is.na(y) & 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
這是一個使用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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.