Заменить значения в data.table агрегированным значением - PullRequest
1 голос
/ 24 апреля 2020

Я хочу вычислить агрегированное значение из data.table и использовать его для замены исходных значений. Я попробовал следующий подход

library(data.table)
(DT <- data.table(grp  = rep(LETTERS[1:3], 3), 
                  val  = 1:9, 
                  val2 = rep(letters[24:26], each = 3)))
#    grp val val2
# 1:   A   1    x
# 2:   B   2    x
# 3:   C   3    x
# 4:   A   4    y
# 5:   B   5    y
# 6:   C   6    y
# 7:   A   7    z
# 8:   B   8    z
# 9:   C   9    z

(agg <- DT[, .SD[which.min(val)], grp])
#    grp val val2
# 1:   A   1    x
# 2:   B   2    x
# 3:   C   3    x

DT[, val3 := "New Value"]
agg[DT, on = "grp"][, .SD, .SDcols = !patterns("^i\\.")]
#    grp val val2      val3
# 1:   A   1    x New Value
# 2:   B   2    x New Value
# 3:   C   3    x New Value
# 4:   A   1    x New Value
# 5:   B   2    x New Value
# 6:   C   3    x New Value
# 7:   A   1    x New Value
# 8:   B   2    x New Value
# 9:   C   3    x New Value

Хотя этот подход работает в этом игрушечном примере, у меня есть пара проблем:

  1. Я хотел бы избежать цепочки в первом место, чтобы избежать массового копирования неиспользуемых столбцов (мой реальный набор данных довольно большой 2e5 x 200) Цитата из data.table FAQ 1.10 :

    Поэтому мы настоятельно рекомендуем X [Y, j] вместо X [Y]

    Помещение части .SD в слот j в первом подмножестве не будет работать

    agg[DT, .SD, on = "grp", .SDcols = !patterns("^i\\.")]
    # Error in do_patterns(colsub, names_x) : Pattern not found: [^i\.]
    
  2. Подход patterns выглядит немного хаки sh и основан на предположении, что data.table всегда будет префиксировать столбцы с Y с i.. Если сопровождающие пакета изменят это по какой-либо причине, мой код сломается.
  3. Я все еще изучаю data.table, и я хочу узнать, каков самый "идиоматический c" способ решения этой проблемы в data.table

Как я могу решить эту проблему, избегая при этом делать ненужные копии для экономии ресурсов?

Примечание. Для чего это важно: я не хочу изменять значения в DT по ссылке.

Ответы [ 2 ]

2 голосов
/ 24 апреля 2020

В зависимости от ваших данных, это может быть более эффективным и давать имена столбцам в явном виде:

library(data.table)
DT <- data.table(grp  = rep(LETTERS[1:3], 3), 
                  val  = 1:9, 
                  val2 = rep(letters[24:26], each = 3))
agg <- DT[, .SD[which.min(val)], grp]
DT[, val3 := "New Value"]

repcols <- setdiff(colnames(agg), "grp")
DT[, (repcols) := agg[DT, .SD, on = .(grp), .SDcols=repcols]][]
#>    grp val val2      val3
#> 1:   A   1    x New Value
#> 2:   B   2    x New Value
#> 3:   C   3    x New Value
#> 4:   A   1    x New Value
#> 5:   B   2    x New Value
#> 6:   C   3    x New Value
#> 7:   A   1    x New Value
#> 8:   B   2    x New Value
#> 9:   C   3    x New Value

Редактировать: В зависимости от дополнительного вопроса, изменение по ссылке может, например, быть непосредственно достигнутым, как это:

library(data.table)
DT <- data.table(grp  = rep(LETTERS[1:3], 3), 
                 val  = 1:9, 
                 val2 = rep(letters[24:26], each = 3))

keepcols <- setdiff(colnames(DT), "grp") 
DT[, val3 := letters[1:9]]
# if you want to keep all of val3; otherwise switch the previous two lines

DT[, (keepcols) := .SD[which.min(val)], by=.(grp), .SDcols=keepcols][]
#>    grp val val2 val3
#> 1:   A   1    x    a
#> 2:   B   2    x    b
#> 3:   C   3    x    c
#> 4:   A   1    x    d
#> 5:   B   2    x    e
#> 6:   C   3    x    f
#> 7:   A   1    x    g
#> 8:   B   2    x    h
#> 9:   C   3    x    i

Создано в 2020-04-24 с помощью представительного пакета (v0.3.0)

1 голос
/ 25 апреля 2020

Назначение по ссылке было бы довольно идиоматическим c. Почему вы указываете, что вы не заинтересованы в этом методе?

DT[agg, on = "grp", val3 := val3]

Или, если agg действительно является совокупностью DT, то это могло бы быть:

DT[, val4 := min(val), by = grp]

      grp   val   val2      val3  val4
   <char> <int> <char>    <char> <int>
1:      A     1      x New Value     1
2:      B     2      x New Value     2
3:      C     3      x New Value     3
4:      A     4      y New Value     1
5:      B     5      y New Value     2
6:      C     6      y New Value     3
7:      A     7      z New Value     1
8:      B     8      z New Value     2
9:      C     9      z New Value     3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...