假設您有一個df以 25 列命名的資料框,其中第一列名為ID,第二至第十三列的名稱為A1to A12,第十四至二十五列的名稱為B1to B12。A 和 B 變數中的值可能是缺失資料。
我面臨的任務是整合資料中的缺失——如果有缺失的條目,比如 A4 的第 8 行,那么 B4 的第 8 行也需要更新為 NA,即使它有一些資料. 反之亦然,如果 B11 的第 19 行缺少條目,則 A11 的第 19 行也需要缺失。
我可以用兩個for回圈來做到這一點:
for(i in 2:13){
for(j in 1:nrow(df)){
if(is.na(df[j,i 12])){
df[j,i] <- NA
}
}
}
for(i in 14:25){
for(j in 1:nrow(df)){
if(is.na(df[j,i-12])){
df[j,i] <- NA
}
}
}
但是,我正在尋找一種不包含for回圈并且最好在 tidyverse 中的解決方案。如何更有效地做到這一點?
uj5u.com熱心網友回復:
這個怎么樣?
#create dataset
library(tidyverse)
library(missForest)
df <- data.frame(id = c(1:10))
df[paste0("a", 1:10)] <- lapply(1:10, function(x) rnorm(10, x))
df[paste0("b", 1:10)] <- lapply(1:10, function(x) rnorm(10, x))
df <- bind_cols(df[1], missForest::prodNA(df[-1], noNA = 0.2)) #add NAs
df
purrr::map 過變數:
df[paste0("a", 1:10)] <- map2(df %>% select(starts_with("a")), df %>% select(starts_with("b")),
~ ifelse(is.na(.y), NA, .x))
df[paste0("b", 1:10)] <- map2(df %>% select(starts_with("b")), df %>% select(starts_with("a")),
~ ifelse(is.na(.y), NA, .x))
df
uj5u.com熱心網友回復:
我們可以轉為長格式,然后在包含 的給定行中NA,將所有值替換為NA,然后轉回寬格式:
spec <-
df %>%
build_longer_spec(cols = -ID,
names_to = c(".value", "set"),
names_pattern = "(. )(\\d )",
values_to = "value")
df %>%
pivot_longer_spec(spec) %>%
print() %>%
# Intermediary long format:
#> # A tibble: 6 x 4
#> ID set A B
#> <int> <chr> <dbl> <dbl>
#> 1 1 1 1 NA
#> 2 1 2 4 10
#> 3 2 1 2 8
#> 4 2 2 5 NA
#> 5 3 1 3 9
#> 6 3 2 NA 12
rowwise(ID, set) %>%
mutate(across(everything(),
~ ifelse(any(is.na(c_across(everything()))), NA, .x))) %>%
pivot_wider_spec(spec)
#> # A tibble: 3 x 5
#> ID A1 A2 B1 B2
#> <int> <dbl> <dbl> <dbl> <dbl>
#> 1 1 NA 4 NA 10
#> 2 2 2 NA 8 NA
#> 3 3 3 NA 9 NA
使用樣本資料:
df <- data.frame(
ID = 1:3,
A1 = c(1, 2, 3),
A2 = c(4, 5, NA),
B1 = c(NA, 8, 9),
B2 = c(10, NA, 12)
)
df
#> ID A1 A2 B1 B2
#> 1 1 1 4 NA 10
#> 2 2 2 5 8 NA
#> 3 3 3 NA 9 12
uj5u.com熱心網友回復:
我們可以在兩個子表中創建 NA 值的掩碼,將它們組合起來,然后將它們應用回兩個子表:
na_mask <- is.na(df[2:13]) | is.na(df[14:25])
df[2:13][na_mask] <- NA
df[14:25][na_mask] <- NA
uj5u.com熱心網友回復:
我相信建議的解決方案應該具有足夠的性能。遍歷列真的沒什么大不了的。
感謝您投票并接受作為答案,如果您喜歡它。
# Create data
nrows <- 10
ncols <- 25
df1 <- as.data.frame(matrix(1:(nrows*ncols), nrow = nrows))
colnames(df1) <- c(
"ID",
paste0("A", 1:12),
paste0("B", 1:12)
)
df1[1:3, c("A1")] <- NA
df1[5:7, c("B5")] <- NA
# Prepare calculation
cols <- as.list(as.data.frame(
matrix(c(paste0("A", 1:12),
paste0("B", 1:12)), nrow = 2, byrow = TRUE)
))
# Do calculation
for (col in cols) {
missing <- is.na(rowSums(df1[col]))
df1[missing, col] <- NA
}
uj5u.com熱心網友回復:
我有一個解決方案,展示了重新格式化資料的一些優勢。
讓我先生成一些資料(因為我們沒有收到)
library(tidyverse)
sample_nrows <- 10
full_df <-
tibble(
ID = rep(seq_len(sample_nrows), each = 12 12),
name = c(str_c("A", 1:12),
str_c("B", 1:12)) %>%
rep(sample_nrows),
value =
rgamma(
n = 12 * 2 * sample_nrows,
shape = sample.int(20, size = 10)
) %>%
round())
full_df %>%
#' add 10% missingness
mutate(value = if_else(rbinom(n(), size = 1, prob = 0.1) %>% as.logical(), NA_real_, value)) %>%
#' reconstruct into wide-format
pivot_wider() %>%
print(n = Inf, width = Inf) ->
partial_df
因此,我們生成gamma-分布式資料,sample_nrows-rows(這是full_df),而我們10%的丟失資料添加到整個事情,并呼叫它partial_df。
這種格式給了我們一個新穎的想法。使用長格式會得到這個結果......
partial_df %>%
pivot_longer(-ID) %>%
tidyr::extract(name, c("name", "var_id"), regex = "(\\D )(\\d )") %>%
pivot_wider(names_from = "name") %>%
mutate(
both_na = is.na(A) | is.na(B),
A = if_else(both_na, NA_real_, A),
B = if_else(both_na, NA_real_, B),
both_na = NULL
) -> partial_df_with_NAs
要恢復原始格式:
partial_df_with_NAs %>%
pivot_wider(names_from = var_id, values_from = c(A,B), names_sep = "") %>%
print(n = Inf, width = Inf)
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/358134.html
標籤:r
上一篇:如何撰寫R函式來反轉互補DNA?
