Can anyone tell me how I can conditionally format my data.table so that numbers >= 1000 do not have decimal places and those below 1000 only have one decimal place?
Here's an image of my data.table
CodePudding user response:
You could use tibbles
which allows to print vectors as you like, see vignette("pillar", package = "vctrs")
.
As shown in this answer on a similar need :
You can get basic control over how a vector is printed in a tibble by providing a format() method
To answer your question, you could create a custom_numeric
class extending numeric
, see vignette("s3-vector", package = "vctrs")
:
library(vctrs)
library(data.table)
library(tibble)
data <- data.table(a=1.11,b=100.11,c=1000.11)
custom_numeric<- function(x = numeric()) {
vec_assert(x, numeric())
new_vctr(x, class = "vctrs_custom_numeric")
}
# Create custom format
format.vctrs_custom_numeric<- function(x,...) {
sapply(vec_data(x),function(x) {if (x>1000) round(x) else x})
}
# Rename custom type name in column header
vec_ptype_abbr.vctrs_custom_numeric <- function(x) {
"numeric"
}
# Apply custom type to all numeric columns
data[,(names(data)):= lapply(.SD,function(col) if (is.numeric(col)) custom_numeric(col) else col )]
# Convert to tibble
tibble::tibble(data)
#> # A tibble: 1 × 3
#> a b c
#> <numeric> <numeric> <numeric>
#> 1 1.11 100.11 1000
CodePudding user response:
Using the dev version of data.table (1.14.3), you could implement a numeric method for format_col generic. More information about customized printing of data.table is available at HERE
Here is an example:
library(data.table)
update.dev.pkg() # to use the dev version
# sample data
set.seed(123)
dt = data.table(a=rnorm(10, 1000, 100), b=rnorm(10, 1000, 100))
# run dt before creating a numeric method for format_col generic
dt
# a b
# <num> <num>
# 1: 943.9524 1122.4082
# 2: 976.9823 1035.9814
# 3: 1155.8708 1040.0771
# 4: 1007.0508 1011.0683
# 5: 1012.9288 944.4159
# 6: 1171.5065 1178.6913
# 7: 1046.0916 1049.7850
# 8: 873.4939 803.3383
# 9: 931.3147 1070.1356
# 10: 955.4338 952.7209
# create a numeric method for format_col
format_col.numeric = function(x, ...) {
ifelse(abs(x)<=1000, round(x), round(x, 1))
}
# printing after
dt
# a b
# <num> <num>
# 1: 944 1122.4
# 2: 977 1036
# 3: 1155.9 1040.1
# 4: 1007.1 1011.1
# 5: 1012.9 944
# 6: 1171.5 1178.7
# 7: 1046.1 1049.8
# 8: 873 803
# 9: 931 1070.1
# 10: 955 953