Множественные попарные различия на основе шаблонов имен столбцов - PullRequest
2 голосов
/ 27 мая 2020

У меня есть data.table, dt:

dt

Id  v1 v2 v3 x1 x2 x3
1   7  1  3  5  6  8
2   1  3  5  6  8  5
3   3  5  6  8  5  1

v1, v2, v3 и x1, x2, x3 - числовые c переменные

Я хочу вычесть ' x 'столбцов из столбцов' v ', т.е. вычислить различия v1 - x1, v2 - x2, et c. В моих реальных данных у меня может быть сотни таких пар переменных.

Желаемый результат:

dt

Id  v1 v2 v3 x1 x2 x3 diff1 diff2 diff3
1   7  1  3  5  6  8   -2     -4    -3
2   1  3  5  6  8  5   -5     -5     0
3   3  5  6  8  5  1   -3      0     5

Я пробовал следующее:

newnames <- paste0("diff", 1:3)
v <- paste0("v", 1:3)
x <- paste0("x", 1:3)
dt[ , c(newnames) := get(v) - get(x)]

Однако в результате получается 3 одинаковых столбца, все из которых содержат разницу v1 - x1.

Я знаю, что возможное решение - что-то вроде

dt[ , .(v1 - x1, v2 - x2, v3 - x3)]

Однако это довольно длинный код с возможным множеством опечаток, если мне нужно ввести 100 имен, не таких простых, как v1 и x1.

Надеюсь, вы поможете мне.

Ответы [ 3 ]

4 голосов
/ 27 мая 2020

Ваши данные выглядят так, как будто они принадлежат к длинному формату, для которого вычисление, которое вам нужно, станет тривиальным:

# reshape
DT_long = melt(DT, id.vars='Id', measure.vars = patterns(v = '^v', x = '^x'))
DT_long
#       Id variable     v     x
# 1:     1        1     7     5
# 2:     2        1     1     6
# 3:     3        1     3     8
# 4:     1        2     1     6
# 5:     2        2     3     8
# 6:     3        2     5     5
# 7:     1        3     3     8
# 8:     2        3     5     5
# 9:     3        3     6     1

Теперь это просто:

DT_long[ , diff := v - x][]
#       Id variable     v     x  diff
# 1:     1        1     7     5     2
# 2:     2        1     1     6    -5
# 3:     3        1     3     8    -5
# 4:     1        2     1     6    -5
# 5:     2        2     3     8    -5
# 6:     3        2     5     5     0
# 7:     1        3     3     8    -5
# 8:     2        3     5     5     0
# 9:     3        3     6     1     5

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

4 голосов
/ 27 мая 2020

Вы можете разделить по тому, содержит ли столбец x, а затем взять разницу в результирующих таблицах данных.

new_cols <- 
  do.call('-', split.default(dt[,-1], grepl('x', names(dt)[-1])))

dt[, paste0('diff', seq_along(new_cols)) := new_cols]

dt
#    Id v1 v2 v3 x1 x2 x3 diff1 diff2 diff3
# 1:  1  7  1  3  5  6  8     2    -5    -5
# 2:  2  1  3  5  6  8  5    -5    -5     0
# 3:  3  3  5  6  8  5  1    -5     0     5

Или используя logi c, аналогичный фрагменту кода в вопросе, который вы могли бы сделать

newnames <- paste0("diff",1:3)
v <- paste0("v",1:3)
x <- paste0("x",1:3)

dt[, (newnames) := Map('-', mget(v), mget(x))]

dt
#    Id v1 v2 v3 x1 x2 x3 diff1 diff2 diff3
# 1:  1  7  1  3  5  6  8     2    -5    -5
# 2:  2  1  3  5  6  8  5    -5    -5     0
# 3:  3  3  5  6  8  5  1    -5     0     5
2 голосов
/ 27 мая 2020

Вы можете использовать set в l oop.

library(data.table)

DT <- fread('Id  v1 v2 v3 x1 x2 x3
1   7  1  3  5  6  8
2   1  3  5  6  8  5
3   3  5  6  8  5  1')

for (i in 1:3) {
  set(DT,j=paste0("Diff_",i),value = DT[[paste0("v",i)]]-DT[[paste0("x",i)]])
}

DT
#>    Id v1 v2 v3 x1 x2 x3 Diff_1 Diff_2 Diff_3
#> 1:  1  7  1  3  5  6  8      2     -5     -5
#> 2:  2  1  3  5  6  8  5     -5     -5      0
#> 3:  3  3  5  6  8  5  1     -5      0      5

Создано 27.05.2020 с помощью пакета (v0.3.0)

...