Ответ 1
Другой подход, который работает, даже если данные не упорядочены:
length(v1)-match(unique(v1),rev(v1))+1
У меня есть неупорядоченный вектор v
, подобный показанному ниже, и хотел бы найти индексы последнего вхождения всех уникальных элементов в списке.
v <- scan(text="1 2 1 2 1 1 1 3 1 2 2 3 3 3 1 1 1 4 1 1 1 4 1 5 5 6
6 2 3 3 4 4 2 2 2 2 2 3 3 3 1 4 4 4 3 2 5 5 5 5")
v
# [1] 1 2 1 2 1 1 1 3 1 2 2 3 3 3 1 1 1 4 1 1 1 4 1 5 5 6 6 2 3 3 4 4 2 2 2 2 2 3 3 3
# [41] 1 4 4 4 3 2 5 5 5 5
Ожидаемый результат (в порядке 1, 2, 3, 4, 5):
41 46 45 44 50
Я знаю, что я могу использовать unique(unlist(v))
для поиска уникальных элементов, но затем как найти индексы их последнего появления? Любая идея?
Спасибо заранее.
Другой подход, который работает, даже если данные не упорядочены:
length(v1)-match(unique(v1),rev(v1))+1
tapply(seq_along(v), v, max)
# 1 2 3 4 5 6
# 41 46 45 44 50 27
Вы можете попробовать rle
, если vector
уже упорядочен. Извлеките длины ($lengths)
, а затем cumsum
. Как я упоминал ранее, это не сработает, если оно не упорядочено (опять же, это зависит от того, что вы действительно хотели). В основном rle
работает, проверяя количество последовательных элементов которые похожи на растяжку. В списке будет lengths
и соответствующем values
.
cumsum(rle(v1)$lengths)
#[1] 28 37 42 46 50
Другим вариантом является группировка последовательности по вектору и получение значения max
для каждого group
. Я предполагаю, что это будет медленным.
unname(cumsum(tapply(seq_along(v1),v1, FUN=which.max)))
#[1] 28 37 42 46 50
Или просто проверьте, совпадает ли предыдущее значение с текущим значением, а затем вставьте TRUE
в качестве последнего элемента и получите индекс TRUE
с помощью which
which(c(v1[-1]!=v1[-length(v1)],TRUE))
#[1] 28 37 42 46 50
Или используйте match
c(match(unique(v1),v1)-1, length(v1))[-1]
#[1] 28 37 42 46 50
Или используйте findInterval
findInterval(unique(v1), v1)
#[1] 28 37 42 46 50
Для нового вектора v2
max.col(t(sapply(unique(v2), `==`, v2)),'last')
#[1] 41 46 45 44 50 27
Или функция, использующая findInterval
после ordering
неупорядоченный вектор
f1 <- function(v){
v1 <- setNames(v, seq_along(v))
ind <- order(v1)
as.numeric(names(v1[ind][findInterval(unique(v1), v1[ind])]))
}
f1(v2)
#[1] 41 46 45 44 50 27
Используя пример (z
) из сообщения @Marat talipov,
f1(z)
#[1] 4 5 3
ПРИМЕЧАНИЕ. Я получаю результат в том порядке, в котором уникальные элементы впервые появились в z
. т.е. 1
, а затем 3
, 2
. Если его нужно заказывать снова на основе значений, это можно сделать, используя order
(как упоминалось @Marat Talipov). Тем не менее, неясно, что OP действительно хотел в таких ситуациях.
v1 <- c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3,
3, 4, 4, 4, 4, 5, 5, 5, 5)
v2 <- c(1, 2, 1, 2, 1, 1, 1, 3, 1, 2, 2, 3, 3, 3, 1, 1, 1, 4, 1, 1,
1, 4, 1, 5, 5, 6, 6, 2, 3, 3, 4, 4, 2, 2, 2, 2, 2, 3, 3, 3, 1,
4, 4, 4, 3, 2, 5, 5, 5, 5)
z <- c(1, 3, 2, 1, 3)
Также можно попробовать
which(c(diff(tmp), TRUE) == 1)
# [1] 28 37 42 46 50
Или аналогично
which(!!c(diff(tmp), TRUE))
Вы можете попробовать использовать .N
из "data.table", например:
library(data.table)
data.table(x, y = seq_along(x))[, y[.N], by = x]
# x V1
# 1: 1 41
# 2: 2 46
# 3: 3 45
# 4: 4 44
# 5: 5 50
# 6: 6 27
Здесь мы в основном создаем двух столбцов data.table
, где первый столбец - ваш вектор, а второй - индексная позиция вашего вектора. .N
указывает, сколько строк в каждой группе (захвачено с помощью by =
), поэтому мы можем просто подмножать значения из y
непосредственно с помощью этой информации.
Еще лучше, как рекомендовано @Arun, мы можем пропустить создание "y" и непосредственно сделать:
data.table(x)[, .I[.N], by=x]
Пример данных:
x <- c(1, 2, 1, 2, 1, 1, 1, 3, 1, 2, 2, 3, 3, 3, 1, 1, 1, 4, 1, 1,
1, 4, 1, 5, 5, 6, 6, 2, 3, 3, 4, 4, 2, 2, 2, 2, 2, 3, 3, 3, 1,
4, 4, 4, 3, 2, 5, 5, 5, 5)
Я сожалею, что, но принятый ответ, а также несколько других ответов, которые должны работать на неупорядоченных векторах, предоставляют неправильное решение.
[EDIT2]
Этот ответ стал предметом споров о том, что следует рассматривать как "правильный" или "неправильный" ответ. Здесь я интерпретировал желаемый результат, так как решение должно быть безымянным вектором, упорядоченным по возрастающему порядку уникальных элементов. Оказалось, что могут существовать другие интерпретации (см. Комментарии ниже), и хотя они не кажутся мне очень очевидными, они определенно имеют право на существование, по крайней мере до тех пор, пока OP не добавит больше примеров, чтобы прояснить ситуацию.
В этом свете было бы лучше сказать, что "ответы, которые воспроизводят образец OP, могут привести к несогласованным результатам в других наборах входных данных относительно упорядочения элементов в выходном векторе" . Непоследовательность частично возникла из-за того, что исходный вопрос ОП был изменен пару раз, и ответы, которые были в полном соответствии с текущим состоянием вопроса, могут не сработать для окончательного состояния вопроса. Мой ответ должен знать читателей об этой ситуации и предложить простое решение для получения решения для конечного состояния вопроса ОП.
Наконец, я понимаю, что мой ответ оказался огромным излишеством, но, учитывая уровень замешательства на этом посту, я думаю, что лучше прояснить ситуацию для будущих заинтересованных читателей.
/[EDIT2]
Я случайно обнаружил эту проблему, когда я начал совместное использование разных решений для проведения сравнительного исследования. Некоторые упомянутые здесь решения не работают, потому что исходный вопрос подразумевает, что входной вектор сортируется в возрастающем порядке, что оказалось не так, поэтому я не обсуждаю их здесь. Решения, которые дают правильные ответы на набор данных примера автора, собирались вместе и завертывались в соответствующие функции:
f.duplicated <- function(z) {
i <- which(!duplicated(z,fromLast=T))
i[order(z[i])]
}
f.match.unique.rev <- function(v1) {
length(v1)-match(unique(v1),rev(v1))+1
}
f.max.col.sapply.unique <- function(v2){
max.col(t(sapply(unique(v2), `==`, v2)),'last')
}
f.data.table <- function(x) {
# data.table(x, y = seq_along(x))[, y[.N], by = x]$V1
setkey(data.table(x, y = seq_along(x)), x)[, y[.N], by = x]$V1
}
f.tapply.seq_along.max <- function(v) {
tapply(seq_along(v), v, max)
}
f.sapply.split.seq_along.max <- function(v) {
sapply(split(seq_along(v), v), max)
}
Затем я написал небольшую функцию для сравнения результатов:
compare.results <- function(z) {
d <- rbind(
f.duplicated(z),
f.match.unique.rev(z),
f.max.col.sapply.unique(z),
f.data.table(z),
f.tapply.seq_along.max(z),
f.sapply.split.seq_along.max(z)
)
rownames(d) <- c(
'f.duplicated',
'f.match.unique.rev',
'f.max.col.sapply.unique',
'f.data.table',
'f.tapply.seq_along.max',
'f.sapply.split.seq_along.max'
)
d
}
и убедитесь, что выбранное решение работает с примерными данными:
z <- c(1,2,1,2, 1, 1, 1, 3, 1, 2, 2, 3, 3, 3, 1, 1, 1, 4, 1, 1, 1, 4, 1, 5, 5, 6, 6, 2, 3, 3, 4, 4, 2, 2, 2, 2, 2, 3, 3, 3, 1, 4, 4, 4, 3, 2, 5, 5, 5, 5)
compare.results(z)
# 1 2 3 4 5 6
# f.duplicated 41 46 45 44 50 27
# f.match.unique.rev 41 46 45 44 50 27
# f.max.col.sapply.unique 41 46 45 44 50 27
# f.data.table 41 46 45 44 50 27
# f.tapply.seq_along.max 41 46 45 44 50 27
# f.sapply.split.seq_along.max 41 46 45 44 50 27
[ПРОБЛЕМА], когда я использовал другой входной вектор 1 3 2 1 3
, для которого правильный ответ 4 3 5
, я обнаружил, что некоторые решения дают неправильный результат:
z <- c(1,3,2,1,3)
compare.results(z)
# 1 2 3
# f.duplicated 4 3 5
# f.match.unique.rev 4 5 3 # ***
# f.max.col.sapply.unique 4 5 3 # ***
# f.data.table 4 3 5
# f.tapply.seq_along.max 4 3 5
# f.sapply.split.seq_along.max 4 3 5
[FIX] Я понял, что проблема с решениями f.match.unique.rev
(принятый ответ) и f.max.col.sapply.unique
заключается в том, что уникальные элементы имеют возрастающий порядок в наборе данных, что в примере автора, но не в моем примере. Вот фиксированные решения:
f.max.col.sapply.unique <- function(v2){
i <- max.col(t(sapply(unique(v2), `==`, v2)),'last')
i[order(v2[i])]
}
f.match.unique.rev <- function(v1) {
i <- length(v1)-match(unique(v1),rev(v1))+1
i[order(v1[i])]
}
[EDIT] Мне сообщили, что исходный результат f.data.table
, который был структурой data.table с двумя столбцами (x
и V1
), содержит всю необходимую информацию чтобы построить ответ в формате, который ожидал автор вопроса. Фактически, ошибка в f.data.table
была введена моим решением использовать столбец V1
как выход функции. Я обновил f.data.table
с помощью модифицированного кода (см. Комментарий ниже), который содержит правильное решение в ожидаемом формате и сохранил старую версию в качестве комментария. Кроме того, я удалил обсуждение решения f.data.table
с конца моего ответа, поскольку он больше не нужен.
Вот еще один подход:
z <- c(1,2,1,2, 1, 1, 1, 3, 1, 2, 2, 3, 3, 3, 1, 1, 1, 4, 1, 1, 1, 4, 1, 5, 5, 6, 6, 2, 3, 3, 4, 4, 2, 2, 2, 2, 2, 3, 3, 3, 1, 4, 4, 4, 3, 2, 5, 5, 5, 5)
i <- which(!duplicated(z,fromLast=T))
i[order(z[i])]
duplicated
возвращает логический вектор, указывающий дубликаты, рассмотренные с обратной стороны. Идея состоит в том, чтобы взять обратный этот вектор для получения логического вектора уникальных элементов и использовать which
для получения индексов.
UPDATE:
Как отмечено в комментарии, мой оригинальный ответ which(!duplicated(z,fromLast=T))
возвратил вектор, который не соответствовал возрастающему порядку элементов во входном векторе. Чтобы исправить эту проблему, я сохранил результат из первой команды как vector i
и переупорядочил ее по мере необходимости.
Просто для удовольствия,
library(dplyr)
#you can use new feature `add_rownames()`
data.frame(x, row=1:length(x)) %>% group_by(x) %>% summarise(max(row))
# x max(row)
#1 1 41
#2 2 46
#3 3 45
#4 4 44
#5 5 50
#6 6 27
для
x <- c(1, 2, 1, 2, 1, 1, 1, 3, 1, 2, 2, 3, 3, 3, 1, 1, 1, 4, 1, 1,
1, 4, 1, 5, 5, 6, 6, 2, 3, 3, 4, 4, 2, 2, 2, 2, 2, 3, 3, 3, 1,
4, 4, 4, 3, 2, 5, 5, 5, 5)
Просто для удовольствия - не векторизованный - но выполняет задание:
sapply(split(seq_along(v), v), max)
# 1 2 3 4 5 6
#41 46 45 44 50 27
С функцией grouping
:
g <- grouping(v)
g[attr(g, "ends")]
# [1] 41 46 45 44 50 27