R, data.table - 为多个表创建新列

R, data.table - create new column for multiple tables

假设我有 2 个 table,他们的名字是:

csvs <- c("jan", "feb")

我希望在每个 table 中创建一个新列,通过简单地使用 df 的名称来表示它们的周期。我的尝试是:

lapply(csvs, function(x)  eval(as.name(x))[, period := x])

是的,我更喜欢应用而不是循环。但是,我收到以下错误:

Invalid .internal.selfref detected and fixed by taking a (shallow) copy of the data.table so that := can add this new column by reference. At an earlier point, this data.table has been copied by R (or was created manually using structure() or similar). Avoid names<- and attr<- which in R currently (and oddly) may copy the whole data.table. Use set* syntax instead to avoid copying: ?set, ?setnames and ?setattr. If this message doesn't help, please report your use case to the data.table issue tracker so the root cause can be fixed or this message improved.

我查阅了浅拷贝,但不明白它如何适用于我的上下文。任何帮助将不胜感激。

T.Fung, 如果您想向每个名为 period 的数据框添加一列,并且该列中的值都是数据框的名称,您可以这样做:

jan$'period' <- 'jan'
feb$'period' <- 'feb'

要循环执行此操作:

# some example data
jan <- data.frame('some_data' = seq(1:5), 'more_data' = seq(1:5))
feb <- data.frame('some_data' = seq(1:5), 'more_data' = seq(1:5))

# vector of your table names
csvs <- c('jan', 'feb')

# loops to add period column to each
for(i in 1:length(csvs)){
  tmp <- paste0(csvs[i],'$period <- \'', csvs[i], '\'',sep = "")
  eval(parse(text = tmp))
}

jan
#>   some_data more_data period
#> 1         1         1    jan
#> 2         2         2    jan
#> 3         3         3    jan
#> 4         4         4    jan
#> 5         5         5    jan

下面是使用应用函数的方法:

# some example data
jan <- data.frame('some_data' = seq(1:5), 'more_data' = seq(6:10))
feb <- data.frame('some_data' = seq(1:5), 'more_data' = seq(6:10))

# vector of your table names
csvs <- c('jan', 'feb')

# This will put all the dataframes into a list
my_fun <- function(csvs){
  tmp <- paste0(csvs,'$period <- \'', csvs, '\'',sep = "")
  eval(parse(text = tmp))
  df <- eval(parse(text=csvs))
  return(df)
}

# apply the function and create a list of dataframes
dfs <- lapply(csvs, FUN = my_fun)

# name the dataframes in the list
names(dfs) <- csvs

# pull the dataframes out of the list and assign to the environment
lapply(names(dfs), function(x) assign(x, dfs[[x]], envir = .GlobalEnv))
#> [[1]]
#>   some_data more_data period
#> 1         1         1    jan
#> 2         2         2    jan
#> 3         3         3    jan
#> 4         4         4    jan
#> 5         5         5    jan
#> 
#> [[2]]
#>   some_data more_data period
#> 1         1         1    feb
#> 2         2         2    feb
#> 3         3         3    feb
#> 4         4         4    feb
#> 5         5         5    feb

# check dataframes for period column
jan
#>   some_data more_data period
#> 1         1         1    jan
#> 2         2         2    jan
#> 3         3         3    jan
#> 4         4         4    jan
#> 5         5         5    jan
feb
#>   some_data more_data period
#> 1         1         1    feb
#> 2         2         2    feb
#> 3         3         3    feb
#> 4         4         4    feb
#> 5         5         5    feb

如果我只是将 eval(as.name(x)) 替换为 get(x)(请参见下面的示例),您的 lapply 解决方案对我来说效果很好 data.table 1.13.6.

test1 <- data.table(a = 1:3, b = 4:6)
test2 <- data.table(a = 7:9, b = 10:12)
dtNames <- c("test1", "test2")

lapply(dtNames, function(x) get(x)[, dtName := x])