为何仅指定单个数据框时data.table::setnames会作用于多个数据框
原理说明
这个现象是两个机制共同作用的结果:
- R本身默认采用*写时复制(Copy-on-Modify)*的内存管理逻辑:使用
<-给变量赋值时,不会立刻为新变量生成完整的对象副本,多个变量会先指向内存中的同一份数据,只有当某个变量触发修改操作时,R才会自动复制出独立副本再执行修改,避免不必要的内存开销。刚执行完df_copy <- df时,df和df_copy的内存地址完全一致,可以用tracemem(df)、tracemem(df_copy)打印地址验证。 data.table::setnames()是为高性能设计的按引用修改函数:它会直接修改对象所在内存地址中存储的列名属性,全程跳过R的写时复制逻辑,不会生成任何对象副本,也不会触发R的自动拷贝流程。
由于setnames()直接改动了两个变量共同指向的内存块里的列名属性,没有发生对象拷贝,所以没有传入函数的df_copy读取列名时,也会拿到修改后的结果。
如果使用R原生的列名修改方式names(df) <- c("col_a", "col_b"),就会触发写时复制机制:R会先为df生成独立的内存副本再修改列名,此时df和df_copy指向不同内存块,df_copy的列名不会发生变化。
解决方法
如果需要保留独立的、不会被同步修改的副本,在调用按引用修改的函数前,显式生成深拷贝即可:
library(data.table) df <- data.frame(col_1 = c(1:9), col_2 = letters[1:9]) # 显式生成独立深拷贝,和原对象内存地址完全分离 df_copy <- copy(df) setnames(x = df, old = c("col_1", "col_2"), new = c("col_a", "col_b")) # 验证结果 names(df) # 输出修改后的列名:"col_a" "col_b" names(df_copy) # 保留原列名:"col_1" "col_2"
内容的提问来源于stack exchange,提问作者emaoca
相关产品推荐
相关产品推荐

