数据表设置功能中的其他条件

时间:2019-09-15 03:02:11

标签: r data.table

我试图基于同一数据表中的多个成对列在数据表中生成新列。例如,newcol1 = b1 / a1,newcol2 = b2 / a2,等等。

如果实际数据表具有数百万行,我可以以一种我认为会很慢的方式来完成它。我所做的是

dt = data.table(
  a1 = c(1, 0, 3, 4, 5), 
  a2 = c(1, 2, 3, 0, 5), 
  b1 = c(6:10),
  b2 = c(6:10) 
)

for (i in 1:2) {
  ind1<-paste("pay", i, sep="")
  ind2<-paste("a", i, sep="")
  ind3<-paste("b", i, sep="")

  dt[[ind1]]<-ifelse(dt[[ind2]]<=0, 100, round((dt[[ind3]]/dt[[ind2]])*100,5))
}

我尝试使用set函数进行改进。有用。但是当我包装一个ifelse条件时,它失败了。

以下代码有效:

ind1<-paste("pay", 1:2, sep="")
ind2<-paste("a", 1:2, sep="")
ind3<-paste("b", 1:2, sep="")

dt[, (ind1):=NA]
set(dt, j=ind1, value=round((dt[, ind3, with=FALSE] / dt[, ind2, with=FALSE])*100,5))

但是下面带有ifelse的那个不起作用:

set(dt, j=ind1, value=ifelse(dt[, ind2, with=FALSE]<=0, 100, 
                             round((dt[, ind3, with=FALSE] / dt[, ind2, with=FALSE])*100,5)))


任何建议都值得赞赏。

我想要的输出应如下所示:

+----+----+----+----+--------+--------+
| a1 | a2 | b1 | b2 |  pay1  |  pay2  |
+----+----+----+----+--------+--------+
|  1 |  1 |  6 |  6 | 600.00 | 600.00 |
|  0 |  2 |  7 |  7 | 100.00 | 350.00 |
|  3 |  3 |  8 |  8 | 266.67 | 266.67 |
|  4 |  0 |  9 |  9 | 225.00 | 100.00 |
|  5 |  5 | 10 | 10 | 200.00 | 200.00 |
+----+----+----+----+--------+--------+

2 个答案:

答案 0 :(得分:3)

您的数据集给我留下了深刻的印象,因为它是长格式的长数据集。如果您没有令人信服的理由保持这种状态,那么我会先将您的数据重整为长格式(使用data.table表示,这意味着melt ing):

dt = melt(
  dt,
  measure.vars = patterns(a = '^a', b = '^b'),
  variable.name = 'idx'
)
head(dt)[]
#    idx a  b
# 1:   1 1  6
# 2:   1 0  7
# 3:   1 3  8
# 4:   1 4  9
# 5:   1 5 10
# 6:   2 1  6

melt版的data.table上,您的问题变得更加简单:

dt[ , pay := ifelse(a <= 0, 100, 100*round(b/a, 5L))][1:6]
 #   idx a  b     pay
# 1:   1 1  6 600.000
# 2:   1 0  7 100.000
# 3:   1 3  8 266.667
# 4:   1 4  9 225.000
# 5:   1 5 10 200.000
# 6:   2 1  6 600.000

请注意,我已经用新贡献的ifelse替换了fifelseifelse仅在开发版本中可用;有关安装此软件的说明,请参见Installation wiki。不过,它应该(主要)可以作为ifelse的直接替代品,因此melt会很好,但在大数据上速度较慢。

如果您希望保持相同的数据形状,则可以dt[ , melt(.SD, measure.vars = patterns(a = '^a', b = '^b'), variable.name = 'idx') ][ , pay := fifelse(a <= 0, 100, 100*round(b/a, 5L)) ][ , dcast(.SD, rowid(idx) ~ idx, value.var = c('a', 'b', 'pay'))] # idx a_1 a_2 b_1 b_2 pay_1 pay_2 # 1: 1 1 1 6 6 600.000 600.000 # 2: 2 0 2 7 7 100.000 350.000 # 3: 3 3 3 8 8 266.667 266.667 # 4: 4 4 0 9 9 225.000 100.000 # 5: 5 5 5 10 10 200.000 200.000 ,添加,重塑如下:

idx

您可以使用:= NULL删除虚拟列sep = '',并使用dcast中的dt[ , c('pay1', 'pay2') := .SD[ , melt(.SD, measure.vars = patterns(a = '^a', b = '^b'), variable.name = 'idx') ][ , pay := fifelse(a <= 0, 100, 100*round(b/a, 5L)) ][ , dcast(.SD, rowid(idx) ~ idx, value.var = c('pay')) ][ , idx := NULL]][] 返回相同的列名称。

或者,您可以这样做,但是直接定义新列:

    #include<stdio.h>
    #define Y 10
    int main()
    {
    #if X && Y || Z
    printf ("A\n");
    #else
    printf("B\n");
    #endif
    }

答案 1 :(得分:2)

运行当前代码后,快速解决方案是将Inf的值替换为100

dt[dt == Inf] <- 100

但是,如果您想在第一步本身中更正输出,我们可以使用Map

library(data.table)
dt[, (ind1) := Map(function(x, y) ifelse(x <= 0 , 1, y/x) * 100, 
               dt[, ind2, with = FALSE], dt[, ind3, with = FALSE])]

dt
#   a1 a2 b1 b2     pay1     pay2
#1:  1  1  6  6 600.0000 600.0000
#2:  0  2  7  7 100.0000 350.0000
#3:  3  3  8  8 266.6667 266.6667
#4:  4  0  9  9 225.0000 100.0000
#5:  5  5 10 10 200.0000 200.0000