Как использовать семейство apply () для определения имен столбцов с максимальными значениями в строках

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

Скажем, у меня есть этот фрейм данных:

set.seed(123)
df <- data.frame(
  V1 = rnorm(10),
  V2 = rnorm(10),
  V3 = rnorm(10)
)

Теперь, чтобы создать новый столбец, который определяет максимальное значение в строке, я использую apply:

df$Max <- apply(df[, 1:3], 1, max, na.rm = TRUE)

Это прекрасно работает:

df
            V1         V2         V3       Max
1  -0.56047565  1.2240818 -1.0678237 1.2240818
2  -0.23017749  0.3598138 -0.2179749 0.3598138
3   1.55870831  0.4007715 -1.0260044 1.5587083
4   0.07050839  0.1106827 -0.7288912 0.1106827
5   0.12928774 -0.5558411 -0.6250393 0.1292877
6   1.71506499  1.7869131 -1.6866933 1.7869131
7   0.46091621  0.4978505  0.8377870 0.8377870
8  -1.26506123 -1.9666172  0.1533731 0.1533731
9  -0.68685285  0.7013559 -1.1381369 0.7013559
10 -0.44566197 -0.4727914  1.2538149 1.2538149

Теперь самое сложное: я хотел бы добавить еще один столбец, назвав столбец, в котором находится максимальное значение. До сих пор я пробовал это расширенное applystatement:

df$Location <- apply(df[, 1:3], 1, function(x) names(x[match(df[,4], x)]))

Кажется, что он захватывает имена, но разбрасывает их по большому количеству дополнительных столбцов:

df
            V1         V2         V3       Max Location.1 Location.2 Location.3 Location.4 Location.5
1  -0.56047565  1.2240818 -1.0678237 1.2240818         V2       <NA>       <NA>       <NA>       <NA>
2  -0.23017749  0.3598138 -0.2179749 0.3598138       <NA>         V2       <NA>       <NA>       <NA>
3   1.55870831  0.4007715 -1.0260044 1.5587083       <NA>       <NA>         V1       <NA>       <NA>
4   0.07050839  0.1106827 -0.7288912 0.1106827       <NA>       <NA>       <NA>         V2       <NA>
5   0.12928774 -0.5558411 -0.6250393 0.1292877       <NA>       <NA>       <NA>       <NA>         V1
6   1.71506499  1.7869131 -1.6866933 1.7869131       <NA>       <NA>       <NA>       <NA>       <NA>
7   0.46091621  0.4978505  0.8377870 0.8377870       <NA>       <NA>       <NA>       <NA>       <NA>
8  -1.26506123 -1.9666172  0.1533731 0.1533731       <NA>       <NA>       <NA>       <NA>       <NA>
9  -0.68685285  0.7013559 -1.1381369 0.7013559       <NA>       <NA>       <NA>       <NA>       <NA>
10 -0.44566197 -0.4727914  1.2538149 1.2538149       <NA>       <NA>       <NA>       <NA>       <NA>
   Location.6 Location.7 Location.8 Location.9 Location.10
1        <NA>       <NA>       <NA>       <NA>        <NA>
2        <NA>       <NA>       <NA>       <NA>        <NA>
3        <NA>       <NA>       <NA>       <NA>        <NA>
4        <NA>       <NA>       <NA>       <NA>        <NA>
5        <NA>       <NA>       <NA>       <NA>        <NA>
6          V2       <NA>       <NA>       <NA>        <NA>
7        <NA>         V3       <NA>       <NA>        <NA>
8        <NA>       <NA>         V3       <NA>        <NA>
9        <NA>       <NA>       <NA>         V2        <NA>
10       <NA>       <NA>       <NA>       <NA>          V3

Как можно аккуратно собрать имена в один столбец df$Location?


person Chris Ruehlemann    schedule 30.03.2020    source источник
comment
Вам нужен names(df)[max.col(df)]?   -  person markus    schedule 30.03.2020
comment
пробовали ли вы это: stackoverflow.com/questions/51613634/ stackoverflow.com/questions/17735859/   -  person Yoan B. M.Sc    schedule 30.03.2020


Ответы (1)


Мы можем использовать max.col

df$Location <- names(df)[1:3][max.col(df[1:3], 'first')]

Если мы хотим использовать apply

 apply(df[1:3], 1, function(x) names(x)[which.max(x)])

Или, если необходимо соответствие столбцу "max", используйте == и подмножество names

apply(df, 1, function(x) names(x)[1:3][x[-length(x)] == x[length(x)]])

В коде OPs он зацикливается со строками только первых 3 столбцов, в то время как match выполняется для всего 4-го столбца для каждой строки

  apply(df[, 1:3], 1, function(x) match(x, df[,4]))

и поскольку есть 3 элемента, в результате получится 3 строки. В коде OP аргументы меняются местами, поэтому длина будет равна nrow для каждой строки.

person akrun    schedule 30.03.2020
comment
Очень красиво и аккуратно. Есть идеи, как можно адаптировать оператор apply для получения того же результата? - person Chris Ruehlemann; 30.03.2020