这是我在堆栈溢出中的第一篇帖子,所以原谅任何错误。我对R语法和数据表也很陌生。
特别是对于数据表,我希望有条件地测试和替换四列中的行值,与第五列中的值进行比较。示例数据如下:
head(loadProfiles)
load_ev_ag load_ev_res load_ev_res_tou load_ev_workplace maxICA
1: 8469.231 2317.895 36700.00 220200.000 8808
2: 8768.000 2609.524 36533.33 36533.333 8768
3: 8744.000 3168.116 27325.00 10409.524 8744
4: 7006.452 3810.526 24133.33 3620.000 8688
5: 5794.595 4660.870 19490.91 2144.000 8576
6: 6057.143 5888.889 16307.69 2208.333 8480
7: 7036.667 7279.310 14073.33 2814.667 8444
8: 8107.692 8107.692 14053.33 3634.483 8432
9: 8138.462 9200.000 11755.56 3992.453 8464
10: 8173.077 10625.000 10119.05 4427.083 8500
我想要做的是在前4列中的每一列上循环以下操作,将每列与第五列中的值进行比较。
loadProfiles[load_ev_ag >= maxICA, load_ev_ag := maxICA]
我想要的结果应如下所示:
head(loadProfiles)
load_ev_ag load_ev_res load_ev_res_tou load_ev_workplace maxICA
1: 8469.231 2317.895 8808 8808 8808
2: 8768.000 2609.524 8768 8768 8768
3: 8744.000 3168.116 8744 8744 8744
4: 7006.452 3810.526 8688 3620.000 8688
5: 5794.595 4660.870 8576 2144.000 8576
6: 6057.143 5888.889 8480 2208.333 8480
7: 7036.667 7279.310 8444 2814.667 8444
8: 8107.692 8107.692 8432 3634.483 8432
9: 8138.462 8464 8464 3992.453 8464
10: 8173.077 8500 8500 4427.083 8500
我试过以下但没有运气:
loadProfileNames <- colnames(loadProfiles)[1:4]
loadProfiles[i = (loadProfileNames) >= maxICA,j = (loadProfileNames) := maxICA]
这会产生以下警告,并且还会将前四列中的所有值更改为等于第五列中的值
Warning message:
In (loadProfileNames) >= maxICA :
longer object length is not a multiple of shorter object length
我还尝试了以下内容,它将符合条件i = (loadProfileNames) >= maxICA
的x行子集更改为maxICA中的前x个条目,而不是更改为maxICA中与行i子集相对应的值。 x行
for(j in loadProfileNames) { set(loadProfiles,i=which(loadProfiles[[j]] >= loadProfiles[["maxICA"]]),j=j,value=loadProfiles[["maxICA"]]) }
并产生以下警告
Warning messages:
1: In set(loadProfiles, i = which(loadProfiles[[j]] >= loadProfiles[["maxICA"]]), :
Supplied 288 items to be assigned to 24 items of column 'load_ev_ag' (264 unused)
2: In set(loadProfiles, i = which(loadProfiles[[j]] >= loadProfiles[["maxICA"]]), :
Supplied 288 items to be assigned to 108 items of column 'load_ev_res' (180 unused)
3: In set(loadProfiles, i = which(loadProfiles[[j]] >= loadProfiles[["maxICA"]]), :
Supplied 288 items to be assigned to 156 items of column 'load_ev_res_tou' (132 unused)
4: In set(loadProfiles, i = which(loadProfiles[[j]] >= loadProfiles[["maxICA"]]), :
Supplied 288 items to be assigned to 156 items of column 'load_ev_workplace' (132 unused)
我在这一点上几乎停滞不前。任何指导都将非常感谢。
答案 0 :(得分:3)
更多&#34; data.table
- way&#34;而不是使用get()
和eval()
通过引用修改loadProfiles
。它使用lapply(.SD, ...)
和.SDcols
来标识要操作的列。使用pmin()
代替ifelse()
。
cols_to_change <- stringr::str_subset(names(loadProfiles), "^load_ev")
loadProfiles[, (cols_to_change) := lapply(.SD, function(x) pmin(x, maxICA)),
.SDcols = cols_to_change]
loadProfiles
# load_ev_ag load_ev_res load_ev_res_tou load_ev_workplace maxICA
# 1: 8469.231 2317.895 8808 8808.000 8808
# 2: 8768.000 2609.524 8768 8768.000 8768
# 3: 8744.000 3168.116 8744 8744.000 8744
# 4: 7006.452 3810.526 8688 3620.000 8688
# 5: 5794.595 4660.870 8576 2144.000 8576
# 6: 6057.143 5888.889 8480 2208.333 8480
# 7: 7036.667 7279.310 8444 2814.667 8444
# 8: 8107.692 8107.692 8432 3634.483 8432
# 9: 8138.462 8464.000 8464 3992.453 8464
#10: 8173.077 8500.000 8500 4427.083 8500
可以重写上述代码以使用set()
函数:
for (j in cols_to_change) {
set(loadProfiles, ,j = j, value = pmin(loadProfiles[[j]], loadProfiles[["maxICA"]]))
}
受到Frank comment的启发,我想知道在性能方面最好的方法是什么。对于基准测试,通过复制OP的数据创建具有100000行的data.table。
# create data.table with 100 000 rows
lp <- copy(loadProfiles0)
dummy <- lapply(1:4, function(x) lp <<-
rbindlist(list(lp, lp, lp, lp, lp, lp, lp, lp, lp, lp)))
nrow(lp)
#100000
由于所有方法都修改了loadProfiles
,我们需要在每次运行之前复制一份。复制操作也进行基准测试以进行比较。
microbenchmark::microbenchmark(
copy = loadProfiles <- copy(lp),
chris = {
loadProfiles <- copy(lp)
for (i in cols_to_change) {
loadProfiles[get(i) >= maxICA, eval(i) := as.double(maxICA)]
}
},
frank = {
loadProfiles <- copy(lp)
for (i in cols_to_change) {
loadProfiles[get(i) >= maxICA, (i) := as.double(maxICA)]
}
},
uwe = {
loadProfiles <- copy(lp)
loadProfiles[, (cols_to_change) := lapply(.SD, function(x) pmin(x, maxICA)),
.SDcols = cols_to_change]
},
set = {
loadProfiles <- copy(lp)
for (j in cols_to_change) {
set(loadProfiles, , j = j, value = pmin(loadProfiles[[j]], loadProfiles[["maxICA"]]))
}
}
)
结果:
#Unit: microseconds
# expr min lq mean median uq max neval
# copy 592.427 1007.012 1170.425 1111.224 1238.281 3977.826 100
# chris 8525.045 10614.394 12704.450 11499.447 12152.475 140577.520 100
# frank 4972.000 6799.118 8566.945 7339.060 7819.344 133202.589 100
# uwe 4201.354 6297.689 6711.409 6585.595 6914.846 10546.996 100
# set 3716.539 5580.662 7138.738 5907.836 6264.840 127311.557 100
弗兰克suggestion从christoph solution删除eval()
已经获得了显着的速度提升。但是,其他两个解决方案仍然更快,set
略微领先。
loadProfiles0 <- fread("load_ev_ag load_ev_res load_ev_res_tou load_ev_workplace maxICA
8469.231 2317.895 36700.00 220200.000 8808
8768.000 2609.524 36533.33 36533.333 8768
8744.000 3168.116 27325.00 10409.524 8744
7006.452 3810.526 24133.33 3620.000 8688
5794.595 4660.870 19490.91 2144.000 8576
6057.143 5888.889 16307.69 2208.333 8480
7036.667 7279.310 14073.33 2814.667 8444
8107.692 8107.692 14053.33 3634.483 8432
8138.462 9200.000 11755.56 3992.453 8464
8173.077 10625.000 10119.05 4427.083 8500")
答案 1 :(得分:1)
你的第一次尝试几乎是正确的:
profilenames <- names(loadProfiles)[1:4]
for (i in profilenames) {
loadProfiles[get(i) >= maxICA, eval(i) := as.double(maxICA)]
}
答案 2 :(得分:0)
您也可以使用lapply
和ifelse
解决此问题,甚至对data.frames
有效:
loadProfiles[loadProfileNames] <- lapply(loadProfiles[loadProfileNames],
function (i) ifelse (i >= loadProfiles$maxICA, loadProfiles$maxICA, i))
对于data.tables
,.SD
变量是一个很好的资源:
loadProfile[, lapply(.SD, function(i) ifelse(i >= maxICA, maxICA, i)), .SDcols = loadProfileNames]