понимание карты поведения против sapply: просмотр имен столбцов, содержащих определенное значение - PullRequest
0 голосов
/ 19 декабря 2018

Мой набор данных кодирует «Не доступно» по-разному в зависимости от переменной (-99, -100, NA).Он имеет сотни переменных, поэтому первым шагом было посмотреть, какие столбцы затронуты, чтобы правильно их перекодировать.

РЕДАКТИРОВАТЬ: благодаря @joran и @G.Гротендик, я получил ответы довольно быстро.Просто для предоставления TL; DR: вариант с colSums, вероятно, лучше всего: быстрый, сжатый и гибкий (хотя его аргументы не так просто поместить в переменную?)

  f1 <- function() {colnames(tbl_df[map_lgl(tbl_df, ~any(. == -100, na.rm = TRUE))])}

  f2 <- function() {names(tbl_df)[colSums(tbl_df == -100) > 0]}

  f3 <- function() {colnames(tbl_df[,sapply(tbl_df, function(x) any(x == -100, na.rm = TRUE))])}

  microbenchmark(f1(), f2(), f3(), unit = "relative")
#> Unit: relative
#>  expr      min       lq     mean   median       uq       max neval
#>  f1() 2.924239 2.694531 2.026845 2.578680 2.604190 0.8291649   100
#>  f2() 1.000000 1.000000 1.000000 1.000000 1.000000 1.0000000   100
#>  f3() 1.113641 1.140000 1.053742 1.167211 1.178409 0.8241631   100

Оригинальный пост продолжается здесь

Я пытался обобщить sapply ответ здесь , и после некоторых проб и ошибок удалось с purrr::map ... Но я неНе понимаю, почему некоторые вещи, которые я пробовал, не работают, в частности, sapply кажется страннымс тем, как sapply работает, но документация и ответы, такие как , этот не совсем подходит для меня ...

Я придумал следующее, которое работает довольноотлично подходит для проверки значений как индивидуально, так и в группах.Я бы приветствовал любые улучшения (например, сохранение значений рядом со столбцами, в которых они были найдены).

colnames(tbl_df[unlist(map(tbl_df, ~any(. %in% c(-99, -100, NA))))])
#> [1] "a" "b" "c"

Кстати, я не совсем понимаю, зачем пытаться достичь подобного втруба дала не то, что нужно

tbl_df %>% 
  filter_all(all_vars(. == -99)) %>% 
  colnames()
#> [1] "a" "b" "c" "d" "e"

Извините, если это похоже на разношерстный набор вопросов;но я был бы признателен за любые разъяснения!

1 Ответ

0 голосов
/ 19 декабря 2018

1) drop = FALSE Подписка на data.frame сбрасывает измерения для результатов 1d, если не используется drop = FALSE, поэтому попробуйте это.(при подписке tibble размеры не отбрасываются.)

# colnames(df[,sapply(df, function(x) any(is.na(x)))])

colnames(df[, sapply(df, function(x) any(is.na(x))), drop = FALSE])
## [1] "a"

или проще:

names(df)[apply(is.na(df), 2, any)]
## [1] "a"

или

names(df)[colSums(is.na(df)) > 0]
## [1] "a"

2) na.rm = TRUE В следующем примере есть NA в первом столбце.Если исключить, что мы получим ответ:

# colnames(tbl_df[,sapply(tbl_df, function(x) any(x == -100))])

colnames(tbl_df[, sapply(tbl_df, function(x) any(x == -100, na.rm = TRUE))])
## [1] "c"

или

names(tbl_df)[colSums(tbl_df == -100, na.rm = TRUE) > 0]
## [1] "c"

или используйте which

names(tbl_df[, sapply(tbl_df, function(x) length(which(x == -100)) > 0)])
## [1] "c"

или

names(tbl_df)[lengths(lapply(as.data.frame(tbl_df == -100), which)) > 0] 
## [1] "c"

или используя which(..., arr.ind = TRUE)

names(tbl_df)[ unique(which(tbl_df == -100, arr.ind = TRUE)[, "col"]) ]
## [1] "c"

3) упрощение Мы можем упростить это, выделив общую часть, которая не зависит от данных, в is.bad:

# colnames(tbl_df[unlist(map(tbl_df, ~any(. %in% c(-99, -100, NA))))])

is.bad <- function(x) any(x %in% c(-99, -100, NA))

names(tbl_df)[ sapply(tbl_df, is.bad) ]
## [1] "a" "b" "c"

или

Filter(function(x) is.bad(tbl_df[[x]]), names(tbl_df))
## [1] "a" "b" "c"

или для другого подхода:

names(tbl_df)[colSums(is.na(tbl_df) | tbl_df == -99 | tbl_df == -100) > 0]
## [1] "a" "b" "c"

4) select_if filter_all с all_vars идет строкойrow и выбирает те строки, для которых все столбцы удовлетворяют условию.Вы хотите идти столбец за столбцом, а не строка за строкой.Используйте select_if вместо:

tbl_df %>%
  select_if(~ any(. == -99)) %>%
  names
## [1] "a" "b"
...