data.table中链式赋值与同括号赋值结果差异的原理探究
为什么data.table里
dt[i, j]和dt[i][,j]的修改结果不一样? 核心原因
这俩操作的本质区别是是否直接修改原表:
dt[i, j]是data.table的原生语法,当j里写了:=赋值时,会直接在原表的内存空间里做原地修改,不会额外生成副本(除非你特意加copy=TRUE参数)。dt[i][,j]是链式调用:第一步dt[i]会生成原表的临时子集副本,第二步的:=只改这个副本,改完之后这个副本没被存到任何变量里,直接被R的垃圾回收机制清理了,原表根本没被触动。
对应你的代码解析
顺序A
- 一开始用
months()给month赋值成字符型,原表的month是字符类型。 dt[id == 1][, month := lubridate::month(d)]:先切出id=1的临时副本,在副本里把month改成数值,但这个副本用完就消失了,原表的month还是字符型。dt[id == 1, month := lubridate::month(d)]:直接在原表的id=1行上修改month列,原表的month列类型直接从字符转成数值(data.table会自动适配列的类型)。
顺序B
- 初始
month同样是字符型。 dt[id == 1, month := lubridate::month(d)]直接修改原表,month变成数值型。- 后面的
dt[id ==1][, month := ...]还是修改临时副本,原表已经是数值型,自然不会有变化。
额外提醒
要是非得用链式操作修改原表,你得把修改后的副本赋值回去,但这样会把原表替换成那个子集,不是修改原表的对应行,比如:
dt <- dt[id == 1][, month := lubridate::month(d)]
实际开发里更推荐用dt[i,j]的原生语法,既高效又不会搞混修改对象。
内容的提问来源于stack exchange,提问作者Kuku
相关产品推荐
相关产品推荐

