минимальное (или максимальное) значение каждой строки в нескольких столбцах - PullRequest
0 голосов
/ 05 мая 2018

Я ищу решение для минимального (или максимального) значения для каждой строки столбцов. Как:

# my data.frame is df:

library(tibble)
df <- tribble(
~name, ~type_1, ~type_2, ~type_3,
"a",   1,   5, 2,
"b",   2,   2, 6,
"c",   3,   8, 2
)

# and output should be result_df:

result_df <- tribble(
~name, ~type_1, ~type_2, ~type_3, ~min_val, ~min_col,
"a",   1,          5,     2,          1, "type_1",
"b",   8,          2,     6,          2, "type_2",
"c",   3,          8,     0,          0 ,"type_3"
)

Я попробовал rowwise и pmax функцию, но она не сработала. Я могу использовать сбор и группировку, но я хочу знать, есть ли решение для столбцов и строк.

Этот подход также будет полезен для средних, медианных функций.

Спасибо за вашу помощь.

Ответы [ 4 ]

0 голосов
/ 06 мая 2018

Довольно обобщенный подход состоит в том, чтобы преобразовать временную форму в длинную форму, что упрощает вычисления - обычная группа mutate.

library(tidyr)
library(dplyr)

df <- tribble(
    ~name, ~type_1, ~type_2, ~type_3,
    "a",   1,   5, 2,
    "b",   8,   2, 6,
    "c",   3,   8, 2
)

df %>% 
    gather(type, type_val, contains('type')) %>% 
    group_by(name) %>% 
    mutate(min_val = min(type_val), 
           min_col = type[type_val == min_val]) %>% 
    spread(type, type_val)
#> # A tibble: 3 x 6
#> # Groups:   name [3]
#>   name  min_val min_col type_1 type_2 type_3
#>   <chr>   <dbl> <chr>    <dbl>  <dbl>  <dbl>
#> 1 a           1 type_1       1      5      2
#> 2 b           2 type_2       8      2      6
#> 3 c           2 type_3       3      8      2

На практике может быть предпочтительнее оставить данные в длинной форме, отбросив вызов spread.

Предостережения:

  • Если более чем одно значение может быть равным минимуму (или максимуму, или медиане, или какому-либо другому), type_val == min_val будет иметь два истинных значения и, следовательно, будет нуждаться в дальнейшем суммировании, чтобы свести его к одному числу, например, как which.min возвращает первый минимум.
  • В масштабах изменение формы может быть дорогостоящим, поэтому предпочтительны более замысловатые, но оптимизированные подходы (например, использование max.col).
0 голосов
/ 05 мая 2018

Возможно, я что-то пропустил; и вы можете захотеть получить ответ типа dplyr ... но вот подход:

Я воссоздал данные, потому что не знал, почему ваши result_df и df имели разные значения

df <- data.frame(name = letters[1:15], as.data.frame(
  lapply(1:3, function(i){
    sample(1:10, 15, T)
  })) %>% setNames(sprintf("type_%s", 1:ncol(.))
))

Затем переберите / примените rowwise к слову и повторите привязку

result_df <- lapply(1:nrow(df), function(i){
  check_df <- df[i,] %>% select(matches("type"))
  r <- check_df[which.min(as.numeric(check_df))]
  data.frame(df[i,], min_val = as.numeric(r), min_col = names(r))
}) %>% rbind_pages()


> df
>    name type_1 type_2 type_3
1     a      9      9      8
2     b      9      7      6
3     c      4      5      5
4     d      7      4      4
5     e      6      5      9
6     f      2      9      7
7     g      9     10      4
8     h      3      5      1
9     i      9      5      5
10    j      1      1      9
11    k      9      5      2
12    l      2      3      4
13    m      4      2      3
14    n      1      3      7
15    o      2      7      6

> result_df
   name type_1 type_2 type_3 min_val min_col
1     a      9      9      8       8  type_3
2     b      9      7      6       6  type_3
3     c      4      5      5       4  type_1
4     d      7      4      4       4  type_2
5     e      6      5      9       5  type_2
6     f      2      9      7       2  type_1
7     g      9     10      4       4  type_3
8     h      3      5      1       1  type_3
9     i      9      5      5       5  type_2
10    j      1      1      9       1  type_1
11    k      9      5      2       2  type_3
12    l      2      3      4       2  type_1
13    m      4      2      3       2  type_2
14    n      1      3      7       1  type_1
15    o      2      7      6       2  type_1
0 голосов
/ 05 мая 2018

Что-то не так с базовым R подходом?

# find the columns in question
mask <- colnames(df)[startsWith(colnames(df), 'type_')]

# apply row-wise and transpose afterwards
df[c('min_val', 'min_col')] <- t(apply(df[mask], 1, function(x) {
  m <- which.min(x)
  (y <- c(x[m], mask[m]))
}))

Это дает

# A tibble: 3 x 6
  name  type_1 type_2 type_3 min_val min_col
  <chr>  <dbl>  <dbl>  <dbl> <chr>   <chr>  
1 a         1.     5.     2. 1       type_1 
2 b         2.     2.     6. 2       type_1 
3 c         3.     8.     2. 2       type_3 

Обратите внимание, что which.min() принимает первое найденное совпадение (во втором ряду два 2).

0 голосов
/ 05 мая 2018

Можете ли вы рассказать немного о логике result_df?
Может быть, можно поделиться своим кодом сбора и группировки?

Придумали следующий промежуточный результат:

df$min_val = apply(df[2:4], 1, min) 
df$min_col = names(df[2:4])[apply( df[2:4], 1, which.min)]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...