упрощает решение для подстановки максимальных данных с несколькими условиями - PullRequest
2 голосов
/ 28 января 2020

Я хочу установить подмножество данных из фрейма данных с несколькими условиями, где одним из них является max или min. Вот что я имею в виду с использованием mtcars:

mtcars[mtcars$qsec==max(mtcars$qsec),]

:

          mpg cyl  disp hp drat   wt qsec vs am gear carb
Merc 230 22.8   4 140.8 95 3.92 3.15 22.9  1  0    4    2

Теперь я хочу получить самую быструю машину (mtcars$qsec==max(mtcars$qsec) ) но только с автомобилей, которые имеют 5 или более передач:

mtcars[mtcars$gear>=5 & mtcars$qsec==max(mtcars$qsec),]

На выходе пустая таблица ...

ДО ВАС ОТВЕТ: Я могу найти способ чтобы решить это самостоятельно, например, сделав это:

my_mtcars=mtcars[mtcars$gear>=5,]
my_mtcars[my_mtcars$qsec==max(my_mtcars$qsec),]

out:

              mpg cyl disp  hp drat    wt qsec vs am gear carb
Lotus Europa 30.4   4 95.1 113 3.77 1.513 16.9  1  1    5    2

Однако в этой конкретной ситуации простота кода является для меня наиболее важным фактором. Можете ли вы предложить какое-либо решение, которое может быть сделано в одной строке кода и не включать в себя ничего более сложного? Это вообще возможно?

Ответы [ 5 ]

1 голос
/ 28 января 2020

Вы можете использовать subset - , фильтровать множественные условия .

subset(subset(mtcars, gear>=5), qsec==max(qsec))
#              mpg cyl disp  hp drat    wt qsec vs am gear carb
#Lotus Europa 30.4   4 95.1 113 3.77 1.513 16.9  1  1    5    2

subset(mtcars[mtcars$gear>=5,], qsec==max(qsec))
#              mpg cyl disp  hp drat    wt qsec vs am gear carb
#Lotus Europa 30.4   4 95.1 113 3.77 1.513 16.9  1  1    5    2

Или для множества различных условий вы можете использовать Reduce.

conditions <- alist(gear>=5, qsec==max(qsec))
Reduce(function(x,y) subset(x,eval(y)), conditions, mtcars)
#              mpg cyl disp  hp drat    wt qsec vs am gear carb
#Lotus Europa 30.4   4 95.1 113 3.77 1.513 16.9  1  1    5    2

Или сохраняя где gear>=5 и используя это для вычисления max.

i <- mtcars$gear>=5
mtcars[i & mtcars$qsec==max(mtcars$qsec[i]),]
#              mpg cyl disp  hp drat    wt qsec vs am gear carb
#Lotus Europa 30.4   4 95.1 113 3.77 1.513 16.9  1  1    5    2

Или используя which и which.max.

i <- which(mtcars$gear>=5)
mtcars[i[which.max(mtcars$qsec[i])],]
#              mpg cyl disp  hp drat    wt qsec vs am gear carb
#Lotus Europa 30.4   4 95.1 113 3.77 1.513 16.9  1  1    5    2
0 голосов
/ 28 января 2020

Я добавляю это как отдельный ответ, потому что это может или не может быть полезным в зависимости от варианта использования. Это имеет тот же отказ от ответственности в отношении rownames, который был удален.

Вы можете сделать довольно простую функцию, чтобы позволить вам последовательно фильтровать.

library(dplyr)
library(rlang)

filter_nested <- function(.data, ...) {

  dots <- enquos(...)

  for (current_filter in seq_along(dots)) {
    .data <- .data %>% 
      filter(!!dots[[current_filter]])
  }

  .data

}

Когда вы примените это, он будет go слева направо от входа, применяя фильтр. Так что сам ваш код был бы чрезвычайно прост.

filter_nested(mtcars, gear >= 5, qsec == max(qsec))

#    mpg cyl disp  hp drat    wt qsec vs am gear carb
# 1 30.4   4 95.1 113 3.77 1.513 16.9  1  1    5    2

Если вы хотите, чтобы два критерия применялись одновременно, вы можете объединить их в один критерий с &.

filter_nested(mtcars, gear >= 5 & hp > 150, qsec == max(qsec))

#    mpg cyl disp  hp drat   wt qsec vs am gear carb
# 1 19.7   6  145 175 3.62 2.77 15.5  0  1    5    6
0 голосов
/ 28 января 2020

Если вы хотите использовать пакет, это довольно просто.

Суть в том, что при этом не будут сохраняться имена строк. У меня никогда не было названий строк, поэтому я считаю, что это достойное решение, но если вы это сделаете, вам придется сначала учесть это (т. Е. tibble::rownames_to_column()).

library(dplyr)

slice(filter(mtcars, gear >= 5), which.max(qsec))
0 голосов
/ 28 января 2020

Вот еще одно базовое решение R, использующее order, то есть

res <- head(mtcars[order(mtcars$gear>=5,mtcars$qsec,decreasing = T),],1)

, такое что

> res
              mpg cyl disp  hp drat    wt qsec vs am gear carb
Lotus Europa 30.4   4 95.1 113 3.77 1.513 16.9  1  1    5    2
0 голосов
/ 28 января 2020

Там должно быть несколько способов. Можно,

filter(mtcars[mtcars$gear >= 5 ,], qsec == max(qsec))

#   mpg cyl disp  hp drat    wt qsec vs am gear carb
#  30.4   4 95.1 113 3.77 1.513 16.9  1  1    5    2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...