我有以下数据和代码来舍入此数据的选定列。表:
> dput(mydf)
structure(list(vnum1 = c(0.590165705411504, -1.39939534199836,
0.720226053660755, -0.253198380120377, -0.783366825121657), vnum2 = c(0.706508400384337,
0.526770398486406, 0.863136084517464, 0.838245498016477, 0.556775856064633
), vch1 = structure(c(2L, 4L, 1L, 3L, 3L), .Label = c("A", "B",
"C", "E"), class = "factor")), .Names = c("vnum1", "vnum2", "vch1"
), row.names = c(NA, -5L), class = c("data.table", "data.frame"
))
> mydf[,round(.SD,1),]
Error in Math.data.frame(list(vnum1 = c(0.590165705411504, -1.39939534199836, :
non-numeric variable in data frame: vch1
> cbind(mydf[,3,with=F], mydf[,1:2,with=F][,round(.SD,1),])
vch1 vnum1 vnum2
1: B 0.6 0.7
2: E -1.4 0.5
3: A 0.7 0.9
4: C -0.3 0.8
5: C -0.8 0.6
有更好的方法(更短的代码)吗?谢谢你的帮助。
答案 0 :(得分:43)
使用dplyr
如果您想一次舍入多个列:
mydf %>% mutate_at(vars(vnum1, vnum2), funs(round(., 1)))
或者,如果要更改“vch1”以外的所有列:
mydf %>% mutate_at(vars(-vch1), funs(round(., 1)))
或者,如果要更改以“vnum”开头的所有列:
mydf %>% mutate_at(vars(starts_with("vnum")), funs(round(., 1)))
或者,如果您只想更改数字列:
mydf %>% mutate_if(is.numeric, ~round(., 1))
你得到:
vnum1 vnum2 vch1
1 0.6 0.7 B
2 -1.4 0.5 E
3 0.7 0.9 A
4 -0.3 0.8 C
5 -0.8 0.6 C
答案 1 :(得分:26)
如果您不介意覆盖原始mydf
:
cols <- names(mydf)[1:2]
mydf[,(cols) := round(.SD,1), .SDcols=cols]
mydf
# vnum1 vnum2 vch1
#1: 0.6 0.7 B
#2: -1.4 0.5 E
#3: 0.7 0.9 A
#4: -0.3 0.8 C
#5: -0.8 0.6 C
答案 2 :(得分:23)
鉴于dplyr::mutate_each
已被弃用,请使用mutate_if
,只有在数字为数字时才能将列舍入为额外好处
mydf %>% mutate_if(is.numeric, round, 1)
答案 3 :(得分:6)
需要(data.table)
简短而明确的解决方案:
mydf[, lapply(.SD, round, 1), vch1]
# vch1 vnum1 vnum2
#1: B 0.6 0.7
#2: E -1.4 0.5
#3: A 0.7 0.9
#4: C -0.3 0.8
#5: C -0.8 0.6
相同,但有描述性细节:
mydf[, lapply(.SD, round, digits = 1), by = vch1]
如果我有很多列,请说:(vnum1,vnum2,vch1,vch2,vbin1,vbin2,vbin3),我想只舍入vnum1和vnum2?
在这种情况下,您可以使用:=
运算符和.SDcols =
参数指定要舍入的列:
mydf[, 1:2 := lapply(.SD, round, digits = 1), by = vch1]
如果您需要对某些列进行舍入并从输出中排除其他列,则可以使用.SDcols =
参数同时执行这两个操作:
mydf[, lapply(.SD, round, digits = 1), by = vch1, .SDcols = "vnum1"]
.SDcols =
可以提供列名或其编号,
作为名称.SDcols = "vnum1"
或数字.SDcols = 1
的单个列
作为名称.SDcols = c("vnum2", "vnum1")
或数字.SDcols = c(2, 1)
的多列
列为名称.SDcols = vnum1:vnum2
或数字.SDcols = 1:2
答案 4 :(得分:2)
截至dplyr
0.8.0,funs()
为soft deprecated。这意味着应该使用list(name = ~f(.))
而不是funs(name = f(.))
。
这里可以用作(通过其名称显式选择列):
mydf %>%
mutate_at(vars(vnum1, vnum2), list(~ round(., 1)))
vnum1 vnum2 vch1
1 0.6 0.7 B
2 -1.4 0.5 E
3 0.7 0.9 A
4 -0.3 0.8 C
5 -0.8 0.6 C
或(选择以vnum
开头的列)
mydf %>%
mutate_at(vars(starts_with("vnum")), list(~ round(., 1)))
或(选择包含vnum
的列)
mydf %>%
mutate_at(vars(contains("vnum")), list(~ round(., 1)))
或(选择与vnum
匹配的列):
mydf %>%
mutate_at(vars(matches("vnum")), list(~ round(., 1)))
或(按名称明确排除列):
mydf %>%
mutate_at(vars(-vch1), list(~ round(., 1)))
或(不包括与vch
匹配的列):
mydf %>%
mutate_at(vars(-matches("vch")), list(~ round(., 1)))
或(选择前两列):
mydf %>%
mutate_at(1:2, list(~ round(., 1)))
或(不包括第三栏):
mydf %>%
mutate_at(-3, list(~ round(., 1)))
或(如果列为数字,则执行操作):
mydf %>%
mutate_if(is.numeric, list(~ round(., 1)))
答案 5 :(得分:1)
到目前为止最短:
mydf[, vch1, round(mydf[, 1:2], 1)]
# vnum1 vnum2 vch1
#1: 0.6 0.7 B
#2: -1.4 0.5 E
#3: 0.7 0.9 A
#4: -0.3 0.8 C
#5: -0.8 0.6 C
有趣的方法。但是,如果我有很多列,比如说:(vnum1,vnum2,vch1,vch2,vbin1,vbin2,vbin3),我想只舍入vnum1和vnum2?此外,关于它如何工作的一些解释将是非常有用的
使用&#34; by =&#34;按舍入列进行分组data.table。
以下是基于此方法解决二级任务的示例。
内置数据集:
>dt <- data.table(names = rownames(datasets::ability.cov$cov), datasets::ability.cov$cov)
>dt
# names general picture blocks maze reading vocab
#1: general 24.641 5.991 33.520 6.023 20.755 29.701
#2: picture 5.991 6.700 18.137 1.782 4.936 7.204
#3: blocks 33.520 18.137 149.831 19.424 31.430 50.753
#4: maze 6.023 1.782 19.424 12.711 4.757 9.075
#5: reading 20.755 4.936 31.430 4.757 52.604 66.762
#6: vocab 29.701 7.204 50.753 9.075 66.762 135.292
简短解决方案:
> dt_round <- dt[, .SD, by = round(dt[, blocks:maze], 1)]
> dt_round
# blocks maze names general picture reading vocab
#1: 33.5 6.0 general 24.641 5.991 20.755 29.701
#2: 18.1 1.8 picture 5.991 6.700 4.936 7.204
#3: 149.8 19.4 blocks 33.520 18.137 31.430 50.753
#4: 19.4 12.7 maze 6.023 1.782 4.757 9.075
#5: 31.4 4.8 reading 20.755 4.936 52.604 66.762
#6: 50.8 9.1 vocab 29.701 7.204 66.762 135.292
初始列顺序:
> whatever <- setcolorder(dt_round, names(dt))
> whatever
# names general picture blocks maze reading vocab
#1: general 24.641 5.991 33.5 6.0 20.755 29.701
#2: picture 5.991 6.700 18.1 1.8 4.936 7.204
#3: blocks 33.520 18.137 149.8 19.4 31.430 50.753
#4: maze 6.023 1.782 19.4 12.7 4.757 9.075
#5: reading 20.755 4.936 31.4 4.8 52.604 66.762
#6: vocab 29.701 7.204 50.8 9.1 66.762 135.292
答案 6 :(得分:1)
功能:
auto_round_dt<- function(dt, ndigits=3, return_copy=TRUE){
dt<- data.table::setDT(dt)
roundme<- names(sapply(dt, class))[which(sapply(dt, class) == "numeric")]
if(return_copy == TRUE){
tmp<- data.table::copy(dt)
out<- tmp[, (roundme):=round(.SD, ndigits), .SDcols=roundme]
return(out)
} else{
return(dt[, (roundme):=round(.SD, ndigits), .SDcols=roundme])
}
}
要返回表的副本而不修改原始表:
newdt<- auto_round_dt(dt=mydt, ndigits = 3, return_copy = TRUE)
并在适当位置修改对象:
auto_round_dt(dt=mydt, ndigits = 3, return_copy = FALSE)
注意:如果将auto_round_dt
设置为data.table
,则不必将return_copy=
的结果分配给新的FALSE
。
答案 7 :(得分:0)
我认为,从解决方案来看,Steven Baupre使用dplyr
的方法是最优雅的,可以选择性地应用于数据帧中的不同列,特别是在计算物理中。
library(dplyr)
gasCriticals %>%
mutate_each(funs(round(., 0)), depth, pres, temp) %>%
mutate_each(funs(round(., 2)), pres.pr, temp.pr, temp.r) %>%
mutate_each(funs(round(., 1)), pres.pc, temp.pc)
如您所见,压力和温度将四舍五入为0位小数;假减压和温度为2分钟;最后,伪临界压力和温度为1位小数。