#r
#r
Вопрос:
У меня есть фрейм данных, как показано ниже. Я хочу переупорядочить фрейм данных на основе столбца «Точка останова».
Ожидаемый результат должен быть таким, как показано ниже
Комментарии:
1. Можете ли вы объяснить это немного лучше? Получается ли так, что каждый раз, когда вы получаете Y в «точке останова», вы хотите поменять местами все строки между этой строкой и предыдущей точкой останова? Что происходит в конце? Почему есть две строки с данными 21,28
2. @Spacedman — Все строки будут перевернуты всякий раз, когда есть точка останова. Кроме того, я хочу добавить все строки (если таковые имеются), присутствующие ниже последней точки останова, как показано на выходе.
3. Вы хотите, чтобы строки ниже последней точки останова включались после повторения последней точки останова ? О, это печально, потому что у меня есть действительно аккуратное решение, если бы этой неправильности не было.
4. Можете ли вы помочь мне с решением, если не было нарушений? Я могу внешне добавить все строки, присутствующие ниже последней точки останова. Меня это не должно беспокоить.
Ответ №1:
С помощью этого примера данных:
df <- data.frame(
Range1 = c(1, 2, 3, 5, 10, 12, 16, 20, 21, 28, 33),
Range2 = c(2, 3, 5, 10, 12, 16, 20, 21, 28, 33, 40),
Breakpoint = c("", "", "", "Y", "", "Y", "", "", "Y", "", ""))
Решение с вырезанием конечных битов является:
Сначала отрежьте висячие биты:
df2 = df[1:max(which(df$Breakpoint=="Y")),]
Затем определите длину каждой группы:
> rgroup=rle(rev(cumsum(rev(df2$Break=="Y"))))$lengths
Получить, где находятся Y:
> Ypos = which(df2$Breakpoint=="Y")
Создайте вектор индекса, который представляет собой позиции Y минус обратную последовательность от 1 до длины фрагмента. Подмножество:
> df2[rep(Ypos, rgroup) - unlist(lapply(rgroup,function(x){1:x})) 1,]
Range1 Range2 Breakpoint
4 5 10 Y
3 3 5
2 2 3
1 1 2
6 12 16 Y
5 10 12
9 21 28 Y
8 20 21
7 16 20
При необходимости добавьте оборванные биты обратно.
[редактировать — добавлена новая версия выше. Код ниже для исторических целей]
Моя старая версия была такой и имела дело с оборванными битами:
> group=rev(cumsum(rev(df$Break=="Y")))
> rbind(do.call(rbind,lapply(split(df[group>0,],-group[group>0]),function(x){x[nrow(x):1,,drop=FALSE]}))[,c("Range1","Range2")],df[max(which(df$Break=="Y")),1:2,drop=FALSE],df[group==0,1:2])
и получаем:
Range1 Range2
-3.4 5 10
-3.3 3 5
-3.2 2 3
-3.1 1 2
-2.6 12 16
-2.5 10 12
-1.9 21 28
-1.8 20 21
-1.7 16 20
9 21 28
10 28 33
11 33 40
Если вам не нравятся имена строк, удалите их. Использует только базовые функции R.
Я не уверен, работает ли это, если после последнего разрыва нет конечного значения, но вы плохо указали проблему, если это может произойти.
Бонусная аннотированная версия:
> group=rev(cumsum(rev(df$Break=="Y")))
Это создает вектор, который начинается с 0 для последней строки и увеличивается каждый раз, когда он находит Y. Переверните это, чтобы получить группирующую переменную для блоков до каждого Y.
Этот бит не будет работать, если cutpaste из-за комментариев, которые я собираюсь сделать:
> rbind(
# we need to bind three things. The reversed chunks, the last break point and
# the trailing stuff:
do.call(
# the trailing stuff is the rbind of the reversed chunks:
rbind,
# split the data into a list of chunks
lapply(
split(df[group>0,],-group[group>0]),
# reverse them
function(x){x[nrow(x):1,,drop=FALSE]}
# and only take the columns we need:
))[,c("Range1","Range2")],
# this is the last Y
df[max(which(df$Break=="Y")),1:2,drop=FALSE],
# this is the trailing rows, get them in order they appear:
df[group==0,1:2])
Подобное аннотирование позволило мне увидеть некоторые оптимизации, которые можно было бы внести, но на данный момент это все.
Ответ №2:
В зависимости от размера вашего data.frame это может быть достигнуто вручную с помощью цикла for .
BreakPoints <- which(!is.na(DF$`break point`))
if(length(breakPoints) > 0){
startIndex <- 1 #Startindex tells me where i should point the breakPoint
for(i in breakPoints){ #Iterate over breakpoints
#Put the break point at the startIndex row
DF[startIndex:i,] <- DF[c(i, startIndex:(i-1), ]
#Update the placement as the next block
startIndex <- i 1
}
}
если ваши данные большие, вероятно, существует более эффективный метод. В общем случае подмножество via [<-.dataframe
выполняется медленно по сравнению с другими методами. Начальный оптимизатор мог бы просто преобразовать приведенный выше код в data.table
формат, где подмножество выполняется намного быстрее.