我试图基于同一数据表中的多个成对列在数据表中生成新列。例如,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 |
+----+----+----+----+--------+--------+
答案 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
替换了fifelse
,ifelse
仅在开发版本中可用;有关安装此软件的说明,请参见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