У меня есть следующий фрейм данных, df1:
ID Group Time1 Time2 Time3
A00194 1 0.733 0.777 0.433
A00195 1 0.903 0.116 0.308
A00198 1 0.422 0.863 0.220
A00199 1 0.485 0.846 0.203
A02111 2 0.682 0.522 0.700
A02114 2 0.699 0.208 0.686
A02116 2 0.911 0.802 0.041
A02197 2 0.083 0.082 0.900
Я хотел бы получить ID и Group с наибольшим значением в каждом Time1:Time3.
Желаемый результат понравится:
ID Group Value Test
A02116 2 0.911 Time1
A00198 1 0.863 Time2
A02197 2 0.900 Time3
Я попробовал следующий код, но мне нужно сделать это три раза, чтобы получить желаемый результат.
df1[which.max(df1$Time1),,c(1:4)]
Как я могу этого добиться?





Данные длинного формата требуют найти максимальное значение каждого Time.
Вы могли бы сделать с dplyr и tidyr.
library(dplyr)
library(tidyr)
df |>
pivot_longer(contains("Time"),names_to = "Test") |>
filter(value == max(value),.by=Test) |>
arrange(Test)
выход
ID Group Test value
<chr> <dbl> <chr> <dbl>
1 A02116 2 Time1 0.911
2 A00198 1 Time2 0.863
3 A02197 2 Time3 0.9
Или с помощью data.table.
df_melt = melt(df,
id.vars = c("ID","Group"),
variable.name = "Test")
df_melt[df_melt[,.I[which.max(value)],by=Test]$V1]
выход
ID Group Test value
1: A02116 2 Time1 0.911
2: A00198 1 Time2 0.863
3: A02197 2 Time3 0.900
library(tidyverse)
df1 %>%
pivot_longer(cols = starts_with("Time"), names_to = "Test", values_to = "Value") %>%
group_by(Test) %>%
slice_max(Value, n = 1) %>%
select(ID, Group, Value, Test)
ID Group Value Test
1 A02116 2 0.911 Time1
2 A00198 1 0.863 Time2
3 A02197 2 0.9 Time3
library(dplyr)
library(tidyr)
df1 %>%
mutate(across(Time1:Time3, ~if_else(.x == max(.x), .x, NA))) %>%
pivot_longer(-c(ID, Group), values_drop_na = TRUE, names_to = "Test")
#> # A tibble: 3 x 4
#> ID Group Test value
#> <chr> <int> <chr> <dbl>
#> 1 A00198 1 Time2 0.863
#> 2 A02116 2 Time1 0.911
#> 3 A02197 2 Time3 0.9
read.table(text= " ID Group Time1 Time2 Time3
A00194 1 0.733 0.777 0.433
A00195 1 0.903 0.116 0.308
A00198 1 0.422 0.863 0.220
A00199 1 0.485 0.846 0.203
A02111 2 0.682 0.522 0.700
A02114 2 0.699 0.208 0.686
A02116 2 0.911 0.802 0.041
A02197 2 0.083 0.082 0.900", header = T, stringsAsFactor = F) -> df1
Вы можете sapply вдоль столбцов и использовать which.max, чтобы получить строку, которая является первым наибольшим значением, которое можно использовать для подмножества и получения желаемого результата.
i <- sapply(df1[3:5], which.max)
cbind(df1[i,1:2], value=mapply(`[[`, df1[3:5], i), test=names(i))
# ID Group value test
#7 A02116 2 0.911 Time1
#3 A00198 1 0.863 Time2
#8 A02197 2 0.900 Time3
Базовый вариант R с max.col
d <- df[max.col(t(df[-(1:2)])), ]
cbind(
d[1:2],
Test = names(d)[-(1:2)],
Value = diag(t(d[-(1:2)]))
)
дает
ID Group Test Value
7 A02116 2 Time1 0.911
3 A00198 1 Time2 0.863
8 A02197 2 Time3 0.900
Двухстрочный с pivot_longer + slice_max:
library(dplyr)
library(tidyr)
pivot_longer(df1, matches("Time"), names_to = "Test") %>%
slice_max(value, by = Test)
# # A tibble: 3 × 4
# ID Group Test value
# <chr> <int> <chr> <dbl>
# 1 A02116 2 Time1 0.911
# 2 A00198 1 Time2 0.863
# 3 A02197 2 Time3 0.9
И тот же подход в базе R:
df_long <- reshape(df1, direction = "long", varying = list(paste0("Time", 1:3)), v.names = "Value")
do.call(rbind, by(df_long, df_long["time"], function(x) x[which.max(x$Value),]) )