组合一系列数据框并为每个数据框创建新列

时间:2012-03-04 01:38:25

标签: r dataframe

我的数据集中每周都有一张带有工作表的Excel文件。每张纸具有相同的行数,每一行在纸张上是相同的(时间段除外...纸张1表示第1周,第2张纸张第2周等)。我试图将所有Excel工作表导入为R中的一个数据框。

例如,我的数据基本上是这样构建的(还有几个列和表):

Week 1 sheet
ID    Gender    DOB    Absences    Lates    Absences_excused
1     M         1997   5           14       5
2     F         1998   4           3        2

Week 2 sheet
ID    Gender    DOB    Absences    Lates    Absences_excused
1     M         1997   2           10       3
2     F         1998   8           2        9

我正在尝试构建一个脚本,它将获取x个工作表并将它们组合成一个数据框,如下所示:

Combined (ideal)
ID    Gender    DOB    Absences.1    Lates.1    Absences.2    Lates.2
1     M         1997   5             14         2             10
2     F         1998   4             3          8             2

我使用gdata导入Excel文件。

我已经尝试创建一个循环(通常不好用于R,我知道......),它将遍历Excel文件中的所有工作表,并将每个工作表添加到列表中作为数据框:

library(gdata)

number_sheets <- 3
all.sheets <- vector(mode="list", length=number_sheets)

for (i in 1:number_sheets) {
  all.sheets[[i]] <- read.xls("/path/to/file.xlsx", sheet=i)
}

这为我提供了一个很好的列表all.sheets,我可以访问,但我不确定从数据框列表中的特定列创建新数据框的最佳方法。

我已经尝试了下面的代码,它通过循环遍历数据框列表来创建一个全新的数据框。在第一个数据框中,它保存所有工作表中一致的列,然后添加特定于周的列。

Cleaned <- data.frame()
number_sheets <- 3

for (i in 1:number_sheets) {
  if (i == 1) {
    Cleaned <- all.sheets[[i]][,c("ID", "Gender", "DOB")]
  }
  Cleaned$Absences.i <- all.sheets[[i]][,c("Absences")]  # wrong... obviously doesn't work... but essentially what I want
  # Other week-specific columns go here... somehow...
}

此代码不起作用,因为Cleaned$Absences.i显然不是您在数据框中创建动态列的方式。

组合一组数据框并为我试图跟踪的每个变量创建新列的最佳方法是什么?

额外的障碍:我还尝试将两列合并,&#34; Absences&#34;和#34; Absences_excused&#34;成为单身&#34;缺席&#34;最后一个数据框中的列,所以我试图让我的解决方案让我对新列进行转换,就像这样(再次,这不是正确的):

Cleaned$Absences.i <- all.sheets[[i]][,c("Absences")] + all.sheets[[i]][,c("Absences_excused")]  

2 个答案:

答案 0 :(得分:7)

合并策略是:

> Week_1_sheet <- read.table(text="ID    Gender    DOB    Absences    Lates
+ 1     M         1997   5           14
+ 2     F         1998   4           3", header=TRUE)
> Week_2_sheet <- read.table(text="ID    Gender    DOB    Absences    Lates
+ 1     M         1997   2           10
+ 2     F         1998   8           2", header=TRUE)
> merge(Week_1_sheet, Week_2_sheet, 1:3)
  ID Gender  DOB Absences.x Lates.x Absences.y Lates.y
1  1      M 1997          5      14          2      10
2  2      F 1998          4       3          8       2

您可以使用names(sheet) <- sub("x", 1, sheet)重命名列,并再次使用y - &gt;重命名列。 2.我认为cbind策略是可以的,但合并可能更好学习。

@TylerRinker提出了关于'by'参数的可接受参数的问题。帮助页面中的相关信息是:“列可以通过名称,数字或逻辑向量指定:名称”row.names“或数字0指定行名称。”

答案 1 :(得分:3)

@Ddin我认为海报的问题比我们相信的例子要复杂一些。我认为海报需要多次合并,如“第1周,第2周第2周等”所示。我的方法有点不同。使用lapply with transform可以在合并之前处理额外的障碍。这是我使用3个数据帧而不是2的合并解决方案。

#First read in three data frames
Week_1_sheet <- read.table(text="ID Gender  DOB Absences Unexcused_Absences Lates
1  1      M 1997        5                  1    14
2  2      F 1998        4                  2     3", header=TRUE)

Week_2_sheet <- read.table(text="ID Gender  DOB Absences Unexcused_Absences Lates
1  1      M 1997        2                  1    10
2  2      F 1998        8                  2     2
3  3      M 1998        8                  2     2", header=TRUE)

Week_3_sheet <- read.table(text="ID Gender  DOB Absences Unexcused_Absences Lates
1  1      M 1997        2                  1    10
2  2      F 1998        8                  2     2", header=TRUE)

#Put them into a list structure
WEEKlist <- list(Week_1_sheet , Week_2_sheet , Week_3_sheet)

#Transform to add the absences and unexcused absences and drop unexcused
lapply(seq_along(WEEKlist), function(x) {
    WEEKlist[[x]] <<- transform(WEEKlist[[x]], Absences=sum(Absences,
        Unexcused_Absences))[, -5]
    }
)

#Rename each data frame in the list with `<<-` that acts on environments
lapply(seq_along(WEEKlist), function(x) {
    y <- names(WEEKlist[[x]])
    names(WEEKlist[[x]]) <<- c(y[1:3], paste(y[4:length(y)], ".", x, sep=""))
    }
)

#loop through and merge by the common columns
DF <- WEEKlist[[1]][, 1:3]
for (.df in WEEKlist) { 
     DF <-merge(DF, .df, by=c('ID', 'Gender', 'DOB'), all=TRUE, suffixes=c("", ""))
}

DF

第二种方法(重命名数据框列后)是使用Reduce: 取自(LINK)

merge.all <- function(frames, by) {
    return (Reduce(function(x, y) {merge(x, y, by = by, all = TRUE)}, frames))
}

merge.all(frames=WEEKlist, by=c('ID', 'Gender', 'DOB'))

我不确定哪一个更快。

编辑:在运行1000次迭代的Windows 7计算机上,Reduce更快:

    test replications elapsed relative user.self sys.self
1   LOOP         1000   10.12  1.62701      7.89        0
2 REDUCE         1000    6.22  1.00000      5.34        0