如何对R data.table中的列列进行操作以输出另一个列表列?

时间:2018-04-20 10:47:19

标签: r data.table

我仍然很难想到如何使用R data.table列作为列表。

这是一个R data.table:

library(data.table)
dt = data.table(
      numericcol = rep(42, 8),
      listcol = list(c(1, 22, 3), 6, 1, 12, c(5, 6, 1123), 3, 42, 1)
  )
> dt
   numericcol        listcol
1:         42        1,22, 3
2:         42              6
3:         42              1
4:         42             12
5:         42    5,   6,1123
6:         42              3
7:         42             42
8:         42              1

我想为numericcollistcol的元素之间的绝对值创建一列:

> dt
   numericcol        listcol    absvals 
1:         42        1,22, 3    41, 20, 39
2:         42              6    36
3:         42              1    41
4:         42             12    30
5:         42    5,   6,1123    37, 36, 1081
6:         42              3    39
7:         42             42    0
8:         42              1    41

所以,我的第一个想法是使用sapply(),如下所示:

dt[, absvals := sapply(listcol, function(x) abs(x-numericcol))]

这输出以下内容:

> dt
   numericcol        listcol absvals
1:         42        1,22, 3      41
2:         42              6      20
3:         42              1      39
4:         42             12      41
5:         42    5,   6,1123      20
6:         42              3      39
7:         42             42      41
8:         42              1      20

因此,absvals现在是一列未列出的元素,每行中都有一个单独的元素,并且是与data.table不同的维度。

(1)如何创建absvals以保留listcol的列表结构?

(2)在这些情况下,如果我只对值的向量感兴趣,R data.table用户如何创建这样的数据结构?

也许

vec = as.vector(dt[, absvals := sapply(listcol, function(x) abs(x-numericcol))])

5 个答案:

答案 0 :(得分:6)

使用mapply的另一种解决方案:

dt[, absvals := mapply(listcol, numericcol, FUN = function(x, y) abs(x-y))]

#output
dt
   numericcol        listcol        absvals
1:         42        1,22, 3       41,20,39
2:         42              6             36
3:         42              1             41
4:         42             12             30
5:         42    5,   6,1123   37,  36,1081
6:         42              3             39
7:         42             42              0
8:         42              1             41

答案 1 :(得分:2)

我认为这基本上是一种逐行操作,所以这种方法肯定会有点不稳定。使用driver.find_element_by_xpath("//ul[@class='results-pagination']/li[last()]/a").click() 中的list列时要记住的关键是data.table假设[.data.table的{​​{1}}输出是j引用列 - 所以你需要再次在list中包含任何list,以使list了解其中只有一列。

我认为这适用于您的情况:

j

dt[ , abs_vals := list(lapply(seq_along(.I), function(ii) abs(listcol[[ii]] - numericcol[ii])))][] # numericcol listcol abs_vals # 1: 42 1,22, 3 41,20,39 # 2: 42 6 36 # 3: 42 1 41 # 4: 42 12 30 # 5: 42 5, 6,1123 37, 36,1081 # 6: 42 3 39 # 7: 42 42 0 # 8: 42 1 41 部分正在处理行方面。

答案 2 :(得分:2)

我们可以使用Map

dt[, absvals := Map(function(x, y) abs(x-y), listcol, numericcol)]
dt
#    numericcol        listcol        absvals
#1:         42        1,22, 3       41,20,39
#2:         42              6             36
#3:         42              1             41
#4:         42             12             30
#5:         42    5,   6,1123   37,  36,1081
#6:         42              3             39
#7:         42             42              0
#8:         42              1             41

purrr::map

dt[, absvals := map2(listcol, numericcol, ~ abs(.x -.y))]

除了循环多次之外,unlist还有一个选项,可以与rep许可的'数字'取得绝对差异。基于'列表中的lengths'。它可能更有效率

dt[, absvals := relist(abs(rep(numericcol, lengths(listcol)) - 
                   unlist(listcol)), skeleton = listcol)]

注意:此处无需复制,因为它与“数字”相同,但rep适用于一般情况

答案 3 :(得分:2)

您可以使用apply()逐行浏览data.table并获取numericollistcol的每个元素之差的绝对值,如下所示; < / p>

dt[, absvals := apply(.SD, 
                      1, 
                      function(x) abs(x$numericcol - x$listcol))]

输出是这样的:

   numericcol        listcol        absvals
1:         42        1,22, 3       41,20,39
2:         42              6             36
3:         42              1             41
4:         42             12             30
5:         42    5,   6,1123   37,  36,1081
6:         42              3             39
7:         42             42              0
8:         42              1             41

答案 4 :(得分:2)

也许你真的不需要列表栏? 看起来你可以做到这一切更简单。

# convert to long format:
dt2 <- dt[, .(var = unlist(listcol)), by = numericcol]
dt2[, absval := abs(var - numericcol)]
dt2
    numericcol  var absval
 1:         42    1     41
 2:         42   22     20
 3:         42    3     39
 4:         42    6     36
 5:         42    1     41
 6:         42   12     30
 7:         42    5     37
 8:         42    6     36
 9:         42 1123   1081
10:         42    3     39
11:         42   42      0
12:         42    1     41

根据我的经验,使用列表对象比使用简单的data.tables更加困难和慢得多。