У меня есть следующий файл 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
Вот один 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
А вот и заказанная версия.
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"
))
@sherlock85 Это довольно просто, но что, если количество случаев >= .5
меньше, чем n
, или этого никогда не происходит?
Спасибо. Приятно слышать. Иногда мне нужно отфильтровать значения на основе n
наибольшего в столбце, но иногда только на основе порогового значения (>= .5
, игнорируя n
). У меня уже есть первое решение благодаря вашему ответу (с циклом for). Было бы идеально сохранить выходной формат первого решения. Буду признателен за ваши предложения.
@ sherlock85 Хорошо, смотрите обновленный ответ.
Спасибо, это работает отлично. Я не хочу беспокоить, но возможно ли отсортировать значения от самого высокого до самого низкого для каждого столбца, как в первом ответе?
@ sherlock85 Конечно, см. Редактировать 2
Спасибо. Потребуется ли много усилий, чтобы изменить цикл for, чтобы получить значения >= 0,5 вместо n наибольшего?