Вычесть постоянное значение на основе позиции - PullRequest
0 голосов
/ 25 февраля 2019

У меня есть DataFrame, в котором хранится информация, подобная этой:

id  store   v1  v2  v3  v4  v5  pos
1   A       5   5   7   7   7   3
2   B       1   1   1   4   5   4

Я хотел бы вычесть значения, основанные на переменной позиции, например, для id = 1 позиция равна 3, поэтому я хотел бывычтите из v3, v4 и v5 константу, равную разности между V3 и v2, которая равна 2 (7-5).Таким образом, результирующий кадр данных должен выглядеть следующим образом:

id  store   v1  v2  v3  v4  v5  pos
1   A       5   5   5   5   5   3
2   B       1   1   1   1   2   4

Для второй строки позиция была 4, поэтому (V4-V3 = 3), поэтому мы вычитаем 3 из переменной, расположенной в позициях 4 и 5.

Спасибо!

Ответы [ 4 ]

0 голосов
/ 26 февраля 2019

Другая возможность tidyverse может быть:

df %>%
 gather(var, val, -c(id, pos, store)) %>%
 arrange(id, var) %>%
 group_by(id) %>%
 mutate(temp = cumsum(ifelse(parse_number(var) == pos, 1, 0) == 1),
        val = ifelse(temp == 1, 
                       val - (val[min(which(temp == 1))] - val[max(which(temp == 0))]), val)) %>%
 select(-temp) %>%
 spread(var, val)

     id store   pos    v1    v2    v3    v4    v5
  <int> <chr> <int> <int> <int> <int> <int> <int>
1     1 A         3     5     5     5     5     5
2     2 B         4     1     1     1     1     2

. Во-первых, он преобразует данные из широкоформатного формата в длинный, исключая переменные «id», «pos» и «store».Во-вторых, он упорядочивает данные по «id» и «var» (который является ключом) и группирует по «id».В-третьих, он проверяет (используя переменную «temp»), равно ли число в ключе (т. Е. Число в именах переменных от «v1» до «v5») равно числу в «pos».Если это так, он присваивает 1, а затем выполняет кумулятивную сумму около 1, таким образом присваивая также всем последующим строкам значение 1. Далее, если значение в «temp» равно 1, оно вычитает значение в последней строке с 0 из значенияв первой строке с 1, а затем вычтите это из всех строк с 1. Наконец, он возвращает данные в их первоначальную форму.

0 голосов
/ 25 февраля 2019

Если ваш фрейм данных не слишком большой, простой цикл for также может легко справиться с задачей в базе R:

# Load your data frame
df <- read.table(header = TRUE, text = "
id  store   v1  v2  v3  v4  v5  pos
1   A       5   5   7   7   7   3
2   B       1   1   1   4   5   4")

# Run through all rows
for (i in seq_len(nrow(df))) {
  p <- df$pos[i]  # Get position
  dif <- df[i, paste0("v", p)]  - df[i, paste0("v", p - 1)]  # Compute difference
  cols <- paste0("v", seq(p, 5))  # Construct colnames to subtract dif from
  df[i, cols] <- df[i, cols] - dif  # Do the subtraction
}
print(df)
#  id store v1 v2 v3 v4 v5 pos
#1  1     A  5  5  5  5  5   3
#2  2     B  1  1  1  1  2   4

Конечно, этот код основывается на некоторых предположениях о том, что ваши реальные данные в реальной жизнивыглядит очень похоже на то, что у вас здесь.А если нет, я думаю, что код легко принимается.

Если вы ненавидите for -петли в R, вы можете заключить его в функцию и скрыть с помощью apply.

0 голосов
/ 26 февраля 2019
#select v columns (v1, v2, ..., v5)
vs <- df[grep('^v', names(df))]
# compute differences (in this case, the vector c(2, 3))
diffs <- vs[cbind(1:nrow(df), df$pos)] - vs[cbind(1:nrow(df), df$pos - 1)]
# subtract diffs from vs if the column is >= pos
df[grep('^v', names(df))] <- vs - diffs*(col(vs) >= df$pos)


df
#   id store v1 v2 v3 v4 v5 pos
# 1  1     A  5  5  5  5  5   3
# 2  2     B  1  1  1  1  2   4

Используемые данные:

df <- read.table(text = '
id  store   v1  v2  v3  v4  v5  pos
1   A       5   5   7   7   7   3
2   B       1   1   1   4   5   4
', header = T)
0 голосов
/ 25 февраля 2019

Занимает несколько строк, но это возможно при использовании функций из тидиверса.Самый важный ключ - взять широкие данные и сделать их длиннее (это работа gather).Затем мы находим где pos == var_pos, вычисляем соответствующую разницу и вычитаем ее из соответствующих значений.Функции separate и unite позволяют конвертировать v1 -> v и 1 и затем возвращаться обратно.

library(tidyverse)
dat %>%
    gather(variable, value, starts_with('v')) %>% # wide to long
    separate(variable, c('variable', 'var_pos'), sep = 1) %>% # v1 -> v, 1
    group_by(id) %>%
    mutate(var_diff = value[var_pos == pos] - value[var_pos == (pos - 1)]) %>%
    mutate(value = ifelse(var_pos >= pos, value - var_diff, value)) %>% # subtract
    unite(variable, variable, var_pos, sep = '') %>% # v,1 -> v1
    select(-var_diff) %>%
    spread(variable, value) # long to wide

    id store   pos    v1    v2    v3    v4    v5
  <int> <chr> <int> <int> <int> <int> <int> <int>
1     1 A         3     5     5     5     5     5
2     2 B         4     1     1     1     1     2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...