Обновить строки в зависимости от значения в следующих строках в нескольких столбцах - PullRequest
0 голосов
/ 08 мая 2018

У меня есть фрейм данных с несколькими тысячами строк и выбранными 2 столбцами, такими как:

col1  col2
2     11
3     11
4     12
4     1
5     1
6     2
1     3
1     3
2     4

В каждом столбце значения в какой-то момент сбрасываются до 1, а затем продолжают накапливаться до некоторого значения перед повторным сбросом. Точка сброса в каждом столбце не зависит от другого. Что мне нужно, так это функция обнаружения сброса и обновления значений ДО этого сброса с отрицательными значениями от -1 до -3 - для каждого столбца в зависимости от его собственного сброса. Таким необходимым результатом будет:

col1  col2
2     -3
3     -2
4     -1
-3     1
-2     1
-1     2
1     3
1     3
2     4

Есть предложения, как это можно сделать? (Dplyr решение было бы очень желательно).

Ответы [ 5 ]

0 голосов
/ 08 мая 2018

Если есть только 3 лага, случай, когда может быть хорошо:

library(dplyr)

d <- tbl_df(read.table(text = "col1  col2
2     11
3     11
4     12
4     1
5     1
6     2
1     3
1     3
2     4", stringsAsFactors = FALSE, header = TRUE ))

d %>%  
  mutate_all(funs(case_when((. > lead(., 1) ~ -1L),
                            (. > lead(., 2) ~ -2L),
                            (. > lead(., 3) ~ -3L),
                            TRUE ~ .)))
0 голосов
/ 08 мая 2018

Вот базовый подход R:

df[] <- lapply(df, function(x) replace(x, which(sign(diff(x)) < 0) - 0:2, -(1:3)))

df
#   col1 col2
# 1    2   -3
# 2    3   -2
# 3    4   -1
# 4   -3    1
# 5   -2    1
# 6   -1    2
# 7    1    3
# 8    1    3
# 9    2    4
0 голосов
/ 08 мая 2018

Используя dplyr и zoo, вы можете сделать это ...

library(zoo)
df2 <- df %>% mutate_all(~pmin(., rollapply(c(diff(.)<0, NA), #find reset point
                                            3, #roll window
                                            function(x) -which(x)[1], #dist to next reset
                                            fill=NA,
                                            align="left"),
                               na.rm=TRUE)) #only replaces non-NA values
df2
  col1 col2
1    2   -3
2    3   -2
3    4   -1
4   -3    1
5   -2    1
6   -1    2
7    1    3
8    1    3
9    2    4
0 голосов
/ 08 мая 2018

Другое базовое решение R:

mydf[] <- lapply(mydf, function(x) {
  w <- which(x == 1 & c(0, head(x,-1)) != 1)
  x[c(sapply(w, `-`, 3:1))] <- -3:-1
  x
})

, что дает:

> mydf
  col1 col2
1    2   -3
2    3   -2
3    4   -1
4   -3    1
5   -2    1
6   -1    2
7    1    3
8    1    3
9    2    4

Старый ответ:

mydf[] <- lapply(mydf, function(x) {
  w <- which(x == 1)
  i <- c(0, diff(w)) != 1
  w <- c(sapply(w[i], `-`, 3:1))
  x[w] <- -3:-1
  x
})
0 голосов
/ 08 мая 2018

Как насчет этого?

f <- function(x) {
    idx <- which(x == 1 & dplyr::lag(x) != 1);
    for (i in 1:length(idx)) x[seq(idx[i] - 3, idx[i] - 1)] <- -3:-1;
    return(x);
}

df[] <- lapply(df, f);
#   col1 col2
#1    2   -3
#2    3   -2
#3    4   -1
#4   -3    1
#5   -2    1
#6   -1    2
#7    1    3
#8    1    3
#9    2    4

Объяснение: Мы определяем функцию f, которая находит точку сброса в векторе (столбце); для каждой точки сброса предыдущие 3 записи затем заменяются на -3:-1. Затем мы применяем эту функцию к каждому столбцу data.frame.


Пример данных

df <- read.table(text =
"col1  col2
2     11
3     11
4     12
4     1
5     1
6     2
1     3
1     3
2     4", header = T)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...