Верхние n строк для каждого столбца в фрейме данных R

У меня есть следующий файл CSV.

,cid1,cid2,cid3
rid1,0.1,0.4,0.3
rid2,1.0,0.1,0.5
rid3,0.2,0.5,0.1
rid4,0.3,0.4,0.8
rid5,0.2,0.3,0.7
rid6,0.9,0.2,0.1
rid7,0.4,0.8,0.9
rid8,0.6,0.5,0.7
rid9,0.3,0.9,0.4

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

cid1  rid2  1.0
cid1  rid6  0.9
cid1  rid8  0.6
                    # Blank lines are only for visibility.
cid2  rid9  0.9
cid2  rid7  0.8
cid2  rid8  0.5

cid3  rid7  0.9
cid3  rid4  0.8
cid3  rid8  0.7

Это то, что у меня есть до сих пор:

csv <- read.csv("input.csv", row.names=1);
n <- 3

for (col in colnames(csv)) {
    print(csv[order(csv[col], decreasing = T)[1:n],][col]);
}

который дает мне почти то, что я хочу.

     cid1
rid2  1.0
rid6  0.9
rid8  0.6
     cid2
rid9  0.9
rid7  0.8
rid3  0.5
     cid3
rid7  0.9
rid4  0.8
rid5  0.7
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
251
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вот один tidyverse способ:

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

library(tidyverse)

csv %>%
  rownames_to_column() %>%
  pivot_longer(cols = -rowname) %>%
  group_by(name) %>%
  slice_max(value, n = 3, with_ties = FALSE)

#  rowname name  value
#  <chr>   <chr> <dbl>
#1 rid2    cid1    1  
#2 rid6    cid1    0.9
#3 rid8    cid1    0.6
#4 rid9    cid2    0.9
#5 rid7    cid2    0.8
#6 rid3    cid2    0.5
#7 rid7    cid3    0.9
#8 rid4    cid3    0.8
#9 rid5    cid3    0.7
Ответ принят как подходящий

В цикле for вы можете объединить верхние n строки с соответствующими rid- и столбцом names в data.frame.

csv <- read.csv("input.csv", row.names=1)

n <- 3
for (k in 1:ncol(csv)) {
  o <- order(-csv[, k])[1:n]
  print(data.frame(cid=names(csv)[k], rid=rownames(csv)[o], v=csv[o, k]))
}
#    cid  rid   v
# 1 cid1 rid2 1.0
# 2 cid1 rid6 0.9
# 3 cid1 rid8 0.6
#    cid  rid   v
# 1 cid2 rid9 0.9
# 2 cid2 rid7 0.8
# 3 cid2 rid3 0.5
#    cid  rid   v
# 1 cid3 rid7 0.9
# 2 cid3 rid4 0.8
# 3 cid3 rid5 0.7

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

n <- 3
lapply(seq(csv), function(x) 
  data.frame(cid=names(csv)[x], rid=rownames(csv), v=csv[, x])[order(-csv[, x]), ][1:n, ])
# [[1]]
#    cid  rid   v
# 2 cid1 rid2 1.0
# 6 cid1 rid6 0.9
# 8 cid1 rid8 0.6
# 
# [[2]]
#    cid  rid   v
# 9 cid2 rid9 0.9
# 7 cid2 rid7 0.8
# 3 cid2 rid3 0.5
# 
# [[3]]
#    cid  rid   v
# 7 cid3 rid7 0.9
# 4 cid3 rid4 0.8
# 5 cid3 rid5 0.7

Редактировать

Чтобы подмножество на пороге вместо порядка, сделайте

th <- .5
for (k in 1:ncol(csv)) {
  rows <- csv[, k] >= th
  print(data.frame(cid=names(csv)[k], rid=rownames(csv)[rows], v=csv[rows, k]))
}
#    cid  rid   v
# 1 cid1 rid2 1.0
# 2 cid1 rid6 0.9
# 3 cid1 rid8 0.6
#    cid  rid   v
# 1 cid2 rid3 0.5
# 2 cid2 rid7 0.8
# 3 cid2 rid8 0.5
# 4 cid2 rid9 0.9
#    cid  rid   v
# 1 cid3 rid2 0.5
# 2 cid3 rid4 0.8
# 3 cid3 rid5 0.7
# 4 cid3 rid7 0.9
# 5 cid3 rid8 0.7

или, используя lapply

th <- .5
lapply(seq(csv), function(x) {
  ss <- csv[[x]] >= th
  data.frame(cid=names(csv)[x], rid=rownames(csv), v=csv[, x])[ss, ]
})
# [[1]]
#    cid  rid   v
# 2 cid1 rid2 1.0
# 6 cid1 rid6 0.9
# 8 cid1 rid8 0.6
# 
# [[2]]
#    cid  rid   v
# 3 cid2 rid3 0.5
# 7 cid2 rid7 0.8
# 8 cid2 rid8 0.5
# 9 cid2 rid9 0.9
# 
# [[3]]
#    cid  rid   v
# 2 cid3 rid2 0.5
# 4 cid3 rid4 0.8
# 5 cid3 rid5 0.7
# 7 cid3 rid7 0.9
# 8 cid3 rid8 0.7

Редактировать 2

А вот и заказанная версия.

th <- .5
lapply(seq(csv), function(x) {
  xo <- csv[order(-csv[, x]), x, F]
  o <- xo[xo >= th,,F]
  cbind(cid=colnames(o), rid=rownames(o), v=unname(o))
})
# [[1]]
# cid  rid   v
# rid2 cid1 rid2 1.0
# rid6 cid1 rid6 0.9
# rid8 cid1 rid8 0.6
# 
# [[2]]
# cid  rid   v
# rid9 cid2 rid9 0.9
# rid7 cid2 rid7 0.8
# rid3 cid2 rid3 0.5
# rid8 cid2 rid8 0.5
# 
# [[3]]
# cid  rid   v
# rid7 cid3 rid7 0.9
# rid4 cid3 rid4 0.8
# rid5 cid3 rid5 0.7
# rid8 cid3 rid8 0.7
# rid2 cid3 rid2 0.5

или

for (x in 1:ncol(csv)) {
  xo <- csv[order(-csv[, x]), x, F]
  o <- xo[xo >= th,,F]
  print(cbind(cid=colnames(o), rid=rownames(o), v=unname(o)))
}
#       cid  rid   v
# rid2 cid1 rid2 1.0
# rid6 cid1 rid6 0.9
# rid8 cid1 rid8 0.6
#       cid  rid   v
# rid9 cid2 rid9 0.9
# rid7 cid2 rid7 0.8
# rid3 cid2 rid3 0.5
# rid8 cid2 rid8 0.5
#       cid  rid   v
# rid7 cid3 rid7 0.9
# rid4 cid3 rid4 0.8
# rid5 cid3 rid5 0.7
# rid8 cid3 rid8 0.7
# rid2 cid3 rid2 0.5

Данные:

csv <- structure(list(cid1 = c(0.1, 1, 0.2, 0.3, 0.2, 0.9, 0.4, 0.6, 
0.3), cid2 = c(0.4, 0.1, 0.5, 0.4, 0.3, 0.2, 0.8, 0.5, 0.9), 
    cid3 = c(0.3, 0.5, 0.1, 0.8, 0.7, 0.1, 0.9, 0.7, 0.4)), class = "data.frame", row.names = c("rid1", 
"rid2", "rid3", "rid4", "rid5", "rid6", "rid7", "rid8", "rid9"
))

Спасибо. Потребуется ли много усилий, чтобы изменить цикл for, чтобы получить значения >= 0,5 вместо n наибольшего?

sherlock85 25.12.2020 19:35

@sherlock85 Это довольно просто, но что, если количество случаев >= .5 меньше, чем n, или этого никогда не происходит?

jay.sf 25.12.2020 19:53

Спасибо. Приятно слышать. Иногда мне нужно отфильтровать значения на основе n наибольшего в столбце, но иногда только на основе порогового значения (>= .5, игнорируя n). У меня уже есть первое решение благодаря вашему ответу (с циклом for). Было бы идеально сохранить выходной формат первого решения. Буду признателен за ваши предложения.

sherlock85 26.12.2020 10:22

@ sherlock85 Хорошо, смотрите обновленный ответ.

jay.sf 26.12.2020 11:10

Спасибо, это работает отлично. Я не хочу беспокоить, но возможно ли отсортировать значения от самого высокого до самого низкого для каждого столбца, как в первом ответе?

sherlock85 26.12.2020 11:33

@ sherlock85 Конечно, см. Редактировать 2

jay.sf 26.12.2020 11:49

Другие вопросы по теме