使用lapply在多个数据框架上创建新变量

时间:2017-06-27 01:39:07

标签: r dataframe transform lapply

我搜索了所有 lapply 问题和解决方案,但这些解决方案似乎都没有针对以下内容进行解决和/或工作......

我有一个列表“temp”,其中包含100个数据帧的名称:“sim_rep1.dat”到“sim_rep100.dat”。

每个数据框有2000个观测值和相同的11个变量:ARAND和w1-w10,所有这些都是数字。

对于所有100个数据帧,我正在尝试创建一个名为“ps_true”的新变量,该变量包含某些“w”变量,每个变量都有一个唯一系数。

对我有用的lapply的唯一用途如下:

lapply(mget(paste0("sim_rep", 1:100,".dat")), transform, 
            ps_true = (1 + exp(-(0.8*w1 - 0.25*w2 + 0.6*w3 - 
                       0.4*w4 - 0.8*w5 - 0.5*w6  + 0.7*w7)))^-1)

当我运行上面的代码时,R循环遍历所有100个数据帧,并在控制台中显示ps_true的新计算值。不幸的是,新列没有添加到数据框中。

当我尝试创建一个功能时,车轮完全关闭。

我尝试了以下不同的变体:

 lapply(temp, function(x){       
        ps_true = (1 + exp(-(0.8*w1 - 0.25*w2 + 0.6*w3 - 
                       0.4*w4 - 0.8*w5 - 0.5*w6  + 0.7*w7)))^-1
   cbind(x, ps_true)
   return(x)
 })
  • FUN中的错误(X [[i]],...):找不到对象'w1'来自上面显示的函数
  • x $ w1中的错误:$运算符对于原子矢量结果无效,如果我尝试引用x $ w1而不是
  • FUN中的错误(X [[i]],...):如果我尝试引用x [[w1]]而不是,则会找到对象'w1'
  • x [[“w1”]]中的错误:如果我尝试引用x [[“w1”]]而不是
  • ,那么下标超出结果

我希望有一些明显的东西让我失踪。我很感激您解决这个令人沮丧的问题的见解和建议。

回应Uwe的附录:

我用来读取所有文件的代码如下:

temp = list.files(pattern='*.dat')
for (i in 1:length(temp)) {
    assign(temp[i], read.csv(temp[i], header=F,sep="",
           col.names = c("ARAND", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10")))
}

2 个答案:

答案 0 :(得分:0)

可能只需要单支架。

test = data.frame('w1' = c(1,2,3),'w2' = c(2,3,4))
temp = list(test,test,test)
temp2 = lapply(temp,function(x){cbind(x,setNames(x['w1'] + x['w2'],'ps_true'))})


temp2
[[1]]
   w1 w2 ps_true
1  1  2       3
2  2  3       5
3  3  4       7

[[2]]
   w1 w2 ps_true
1  1  2       3
2  2  3       5
3  3  4       7

[[3]]
   w1 w2 ps_true
1  1  2       3
2  2  3       5
3  3  4       7

答案 1 :(得分:0)

根据OP,有100个data.frames具有相同的列名称。 OP希望使用完全相同的公式在所有data.frames中创建新列。

这表明数据结构设计存在根本缺陷。我想,没有数据库管理员会创建100个相同的表,其中只有数据内容不同。相反,他会创建一个表,其中包含一个标识每行原点的附加列。然后,所有后续操作将应用于一个表,而不是为每个表重复。

在R中,data.table包具有方便的rbindlist()功能,可用于此目的:

library(data.table)   # CRAN version 1.10.4 used
# get list of data.frames from the given names and
# combine the rows of all data sets into one large data.table
DT <- rbindlist(mget(temp), idcol = "origin")
# now create new column for all rows across all data sets
DT[, ps_true := (1 + exp(-(0.8*w1 - 0.25*w2 + 0.6*w3 - 
                            0.4*w4 - 0.8*w5 - 0.5*w6  + 0.7*w7)))^-1]
DT
                origin ARAND   w1   w2   w3   w4   w5   w6   w7   w8   w9  w10   ps_true
     1:   sim_rep1.dat  -0.6 -0.5  0.2 -0.7  0.5  2.4 -0.2 -0.9 -1.1  0.3 -0.8 0.0287485
     2:   sim_rep1.dat  -0.2  0.2  0.7  1.0  1.8 -0.2  0.8  0.3 -1.3 -1.6 -0.2 0.4588433
     3:   sim_rep1.dat   1.6 -0.5  0.7 -0.7 -1.7  0.9 -1.2 -1.0  1.1 -0.3 -2.1 0.2432395
     4:   sim_rep1.dat   0.1  1.2 -1.3 -0.1  0.3 -0.6  0.4  0.3  0.8 -1.2 -1.7 0.8313184
     5:   sim_rep1.dat   0.1  0.2 -2.0  0.6 -0.3  0.2  0.2  0.5 -0.9 -0.8 -1.1 0.7738186
    ---                                                                                 
199996: sim_rep100.dat   0.1 -1.4  1.6 -0.7 -1.0 -0.6  0.8 -0.6 -0.5 -0.4 -0.8 0.1323889
199997: sim_rep100.dat   0.3  1.3 -2.4 -0.7 -0.4  0.0  1.0 -0.2  1.0 -0.1  0.3 0.6769959
199998: sim_rep100.dat   0.3  1.2  0.0 -1.3 -0.8 -0.7 -0.3  0.1  0.9  0.9 -1.3 0.7824498
199999: sim_rep100.dat   0.5 -0.7  0.2  0.5  1.1 -0.3  0.3 -0.5 -0.8  1.9 -0.7 0.2669799
200000: sim_rep100.dat  -0.5  1.1  0.8  0.2 -0.6 -0.5 -0.4  1.1 -1.8  0.9 -1.3 0.9175867

DT现在包含200 K行。性能没有理由担心,因为data.table是为了有效地处理大型(甚至更大)数据而构建的。

如果需要单独处理各个数据集的数据,则可以识别每行的来源。如,

DT[origin == "sim_rep47.dat"]
             origin ARAND   w1   w2   w3   w4   w5   w6   w7   w8   w9  w10   ps_true
   1: sim_rep47.dat  -0.6 -0.5  0.2 -0.7  0.5  2.4 -0.2 -0.9 -1.1  0.3 -0.8 0.0287485
   2: sim_rep47.dat  -0.2  0.2  0.7  1.0  1.8 -0.2  0.8  0.3 -1.3 -1.6 -0.2 0.4588433
   3: sim_rep47.dat   1.6 -0.5  0.7 -0.7 -1.7  0.9 -1.2 -1.0  1.1 -0.3 -2.1 0.2432395
   4: sim_rep47.dat   0.1  1.2 -1.3 -0.1  0.3 -0.6  0.4  0.3  0.8 -1.2 -1.7 0.8313184
   5: sim_rep47.dat   0.1  0.2 -2.0  0.6 -0.3  0.2  0.2  0.5 -0.9 -0.8 -1.1 0.7738186
  ---                                                                                
1996: sim_rep47.dat   0.1 -1.4  1.6 -0.7 -1.0 -0.6  0.8 -0.6 -0.5 -0.4 -0.8 0.1323889
1997: sim_rep47.dat   0.3  1.3 -2.4 -0.7 -0.4  0.0  1.0 -0.2  1.0 -0.1  0.3 0.6769959
1998: sim_rep47.dat   0.3  1.2  0.0 -1.3 -0.8 -0.7 -0.3  0.1  0.9  0.9 -1.3 0.7824498
1999: sim_rep47.dat   0.5 -0.7  0.2  0.5  1.1 -0.3  0.3 -0.5 -0.8  1.9 -0.7 0.2669799
2000: sim_rep47.dat  -0.5  1.1  0.8  0.2 -0.6 -0.5 -0.4  1.1 -1.8  0.9 -1.3 0.9175867

提取属于数据集sim_rep47.dat的所有行。

数据

为了测试和演示,我使用以下代码创建了100个样本数据框架:

# create vector of file names
temp <- paste0("sim_rep", 1:100, ".dat")
# create one sample data.frame
nr <- 2000L
nc <- 11L
set.seed(123L)
foo <- as.data.frame(matrix(round(rnorm(nr * nc), 1), nrow = nr))
names(foo) <- c("ARAND", paste0("w", 1:10))
str(foo)
# create 100 individually named data.frames by "copying" foo
for (t in temp) assign(t, foo)
# print warning message on using assign
fortunes::fortune(236)
# verify objects have been created
ls()

附录:一次阅读所有文件

OP已命名单个data.frames sim_rep1.datsim_rep2.dat等,其类似于典型的文件名。如果OP确实在磁盘上有100个文件,我想建议一种方法一次读取所有文件。我们假设所有文件都存储在一个目录中。

# path to data directory
data_dir <- file.path("path", "to", "data", "directory")
# create vector of file paths
files <- dir(data_dir, pattern = "sim_rep\\d+\\.dat", full.names = TRUE)
# read all files and create one large data.table
# NB: it might be necessary to add parameters to fread() 
# or to use another file reader depending on the file type
DT <- rbindlist(lapply(files, fread), idcol = "origin")
# rename origin to contain the file names without path
DT[, origin := factor(origin, labels = basename(files))]
DT
               origin ARAND   w1   w2   w3   w4   w5   w6   w7   w8   w9  w10   ps_true
     1:  sim_rep1.dat  -0.6 -0.5  0.2 -0.7  0.5  2.4 -0.2 -0.9 -1.1  0.3 -0.8 0.0287485
     2:  sim_rep1.dat  -0.2  0.2  0.7  1.0  1.8 -0.2  0.8  0.3 -1.3 -1.6 -0.2 0.4588433
     3:  sim_rep1.dat   1.6 -0.5  0.7 -0.7 -1.7  0.9 -1.2 -1.0  1.1 -0.3 -2.1 0.2432395
     4:  sim_rep1.dat   0.1  1.2 -1.3 -0.1  0.3 -0.6  0.4  0.3  0.8 -1.2 -1.7 0.8313184
     5:  sim_rep1.dat   0.1  0.2 -2.0  0.6 -0.3  0.2  0.2  0.5 -0.9 -0.8 -1.1 0.7738186
    ---                                                                                
199996: sim_rep99.dat   0.1 -1.4  1.6 -0.7 -1.0 -0.6  0.8 -0.6 -0.5 -0.4 -0.8 0.1323889
199997: sim_rep99.dat   0.3  1.3 -2.4 -0.7 -0.4  0.0  1.0 -0.2  1.0 -0.1  0.3 0.6769959
199998: sim_rep99.dat   0.3  1.2  0.0 -1.3 -0.8 -0.7 -0.3  0.1  0.9  0.9 -1.3 0.7824498
199999: sim_rep99.dat   0.5 -0.7  0.2  0.5  1.1 -0.3  0.3 -0.5 -0.8  1.9 -0.7 0.2669799
200000: sim_rep99.dat  -0.5  1.1  0.8  0.2 -0.6 -0.5 -0.4  1.1 -1.8  0.9 -1.3 0.9175867

现在,所有数据集都存储在一个包含200 k行的大型data.table DT中。但是,数据集的顺序不同,因为files按字母顺序排序,即

head(files)
[1] "./data/sim_rep1.dat"   "./data/sim_rep10.dat"  "./data/sim_rep100.dat"
[4] "./data/sim_rep11.dat"  "./data/sim_rep12.dat"  "./data/sim_rep13.dat"