data.table中自定义函数无法作用于所有行的原因及解决方法
问题分析与修复方案
为什么你的代码失效?
你这段代码的问题出在对lapply(.SD, ...)的理解上:
- 当你指定
.SDcols = "ID"时,.SD代表的是整个ID列(一个向量),而不是单个ID元素。所以function(x)里的x是所有ID组成的向量,不是单个字符串。 strsplit(x, "-")对向量处理后会返回一个列表,每个列表项对应一个ID拆分后的结果。但你用[[1]][1]只取了列表的第一个元素(也就是第一个ID"1234-123"拆分出的"1234"),然后把这个值重复赋值给了整个new列,所以最终结果全是同一个值,完全不符合你提取每个ID前半部分的需求。
几种修复方法
下面给你几个高效的修复方案,从简洁到通用都有:
方法1:用data.table专属的tstrsplit(推荐)
tstrsplit是data.table专门为拆分字符串设计的函数,它会自动把拆分后的结果转置成列,直接取第一列就能得到每个ID的前半部分:
library(data.table) demo <- data.table(ID = c("1234-123", "1521-111", "1214-113", "1412-912")) # 只提取前半部分 demo[, new := tstrsplit(ID, "-")[[1]]] # 如果需要同时保留后半部分,可以这样写: demo[, c("new", "suffix") := tstrsplit(ID, "-")]
方法2:用正则表达式sub提取
如果只是简单提取-之前的内容,用sub更简洁,不需要处理列表:
demo[, new := sub("-.*", "", ID)]
这里的正则-.*表示匹配-以及后面的所有内容,用空字符串替换,就剩下了-之前的部分。
方法3:用sapply处理拆分后的列表
如果你想保留类似原代码的思路,可以用sapply遍历strsplit返回的列表,取每个列表项的第一个元素:
demo[, new := sapply(strsplit(ID, "-"), `[`, 1)]
sapply会自动把列表转换成向量,正好适合赋值给new列。
内容的提问来源于stack exchange,提问作者Snowflake
相关产品推荐
相关产品推荐

