假设我有以下数据:
kat = c("a.b.c.d.e.f", "a.c.e.d.f.s", "a.v")
以R为基数的所需输出:
> splitted = strsplit(kat, "[.]")
> kat2 = sapply(splitted, function(x) paste(x[1:min(5, length(x))], collapse = "."))
> kat2
[1] "a.b.c.d.e" "a.c.e.d.f" "a.v"
问题:如何使用data.table(以“可读”方式):
我知道该怎么做技术上正确的:
dat = data.table(kat = kat)
dat[, kat := sapply(strsplit(kat, "[.]"),
function(x) paste(x[1:min(5, length(x))], collapse = "."))]
但是我发现它不是很可读,特别是如果我为更长的时间这样做。
我必须为每个操作创建一个函数吗?
kat3 = function(str){
splitted = strsplit(str, "[.]")
sapply(splitted, function(x) paste(x[1:min(5, length(x))], collapse = "."))
}
dat[, kat := kat3(kat)][]
或者是否有可能在data.table的索引编制中做到这一点?
dat[, kat := function(kat){
splitted = strsplit(kat, "[.]")[[1]]
paste(splitted[1:min(5, length(splitted))], collapse = ".")
}, ]
答案 0 :(得分:1)
您最后一次尝试失败,因为您需要将向量返回给kat。 sapply
或Vectorize
可以帮上忙。
kat <- c("a.b.c.d.e.f", "a.c.e.d.f.s", "a.v")
library(data.table)
dat = data.table(kat = kat)
# error - function take a first element and return its transformation
dat[, kat2 := function(kat){
splitted = strsplit(kat, "[.]")[[1]]
paste(splitted[1:min(5, length(splitted))], collapse = ".")
}, ]
#> Error in `[.data.table`(dat, , `:=`(kat2, function(kat) {: RHS of assignment is not NULL, not an an atomic vector (see ?is.atomic) and not a list column.
smt <- function(kat){
splitted = strsplit(kat, "[.]")[[1]]
paste(splitted[1:min(5, length(splitted))], collapse = ".")
}
# to confirm
smt(kat)
#> [1] "a.b.c.d.e"
# use vectorize or sapply
smt_v <- Vectorize(smt)
smt_v(kat)
#> a.b.c.d.e.f a.c.e.d.f.s a.v
#> "a.b.c.d.e" "a.c.e.d.f" "a.v"
sapply(kat, smt)
#> a.b.c.d.e.f a.c.e.d.f.s a.v
#> "a.b.c.d.e" "a.c.e.d.f" "a.v"
如果要对许多变量执行操作,则可以遍历它们或使用lapply和.SDcols参数。如果编写function.R
脚本并进行采购有很多转换,则可能是进行进一步研究的最佳方法。 :)
答案 1 :(得分:1)
使用正则表达式解决问题的另一种方法,我们提取单词直到出现第n个字符(这里是一个点)。这避免了字符串的拆分和连接步骤。
从here和@Nathan Werth获得正则表达式帮助
library(data.table)
dat[, kat1 := stringr::str_extract(kat, "^(([^\\.]*\\.){0,4}[^\\.]*)")]
dat
# kat kat1
#1: a.b.c.d.e.f a.b.c.d.e
#2: a.c.e.d.f.s a.c.e.d.f
#3: a.v a.v