Округление выбранных столбцов data.table в R
У меня есть следующие данные и код для округления выбранных столбцов этого data.table:
> 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
Есть ли лучший метод (более короткий код)? Спасибо за вашу помощь.
Ответы
Ответ 1
Если вы не возражаете переписать свой оригинальный 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
Использование 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
Ответ 3
Учитывая, что dplyr::mutate_each
устарела, используйте mutate_if
с дополнительным преимуществом округления столбца, только если он числовой
mydf %>% mutate_if(is.numeric, round, 1)
Ответ 4
требуется (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
Ответ 5
Начиная с dplyr
0.8.0, funs()
является мягким устаревшим. Это означает, что вместо funs(name = f(.))
следует использовать list(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
Однако в этом случае нет необходимости использовать какие-либо из них (поскольку существует только одна функция), и подход из @Arthur Yip можно применять ко всем сценариям.
Выбор столбцов явно по их именам:
mydf %>%
mutate_at(vars(vnum1, vnum2), round, 1)
Или выберите столбцы, которые начинаются с vnum
:
mydf %>%
mutate_at(vars(starts_with("vnum")), round, 1)
Или выберите столбцы, содержащие vnum
:
mydf %>%
mutate_at(vars(contains("vnum")), round, 1)
Или выберите столбцы, которые соответствуют vnum
:
mydf %>%
mutate_at(vars(matches("vnum")), round, 1)
Или исключить столбец явно по его имени:
mydf %>%
mutate_at(vars(-vch1), round, 1)
Или исключая соответствующие столбцы vch
:
mydf %>%
mutate_at(vars(-matches("vch")), round, 1)
Или выбрав первые два столбца:
mydf %>%
mutate_at(1:2, round, 1)
Или исключая третий столбец:
mydf %>%
mutate_at(-3, round, 1)
Ответ 6
Короче говоря:
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? Кроме того, некоторые объяснения относительно того, как он работает, будут очень полезны
Он группируется округленными столбцами, используя "by =" 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
Ответ 7
Я думаю, что из решений, который Стивен Баупре использует 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 десятичного знака.