将多个数据帧与R中的重复行合并

时间:2016-06-21 18:11:46

标签: r dataframe merge

对于这种事情,R相对较新,搜索了一下,找不到有用的东西。

我有大约150个.csv文件,每个文件有40,000到60,000行,我试图将每个列中的3列合并为1个大数据帧。我有一个小脚本,从每个文件中提取3个感兴趣的列(" id"," name"和#34; value")并通过" ID"和"名称"使用更大的数据框" MergedData"。这是我的代码(我确定这是一种非常低效的方式,这对我来说现在还可以,但我当然可以选择更好的选项!):

file_list <- list.files()

for (file in file_list){

  if(!exists("MergedData")){
    MergedData <- read.csv(file, skip=5)[ ,c("id", "name", "value")]
    colnames(MergedData) <- c("id", "name", file)
  }

  else if(exists("MergedData")){
    temp_data <- read.csv(file, skip=5)[ ,c("id", "name", "value")]
    colnames(temp_data) <- c("id", "name", file)
    MergedData <- merge(MergedData, temp_data, by=c("id", "name"), all=TRUE)
    rm(temp_data)
  }
}

并非每个文件都具有相同的行数,但许多行对于许多文件是通用的。我没有包含行的列表,所以我包括all = TRUE来追加MergedData文件中尚不存在的新行。

我的问题是:许多文件包含2-4行,相同的&#34; id&#34;和&#34;名称&#34;条目,但不同的&#34;值&#34;条目。因此,当我合并它们时,我最终会为每个可能的组合添加行,这会快速失控。最令人沮丧的是,这些重复内容对我来说都没有任何意义。有没有一种简单的方法来获取第一个条目的值,只是忽略任何进一步的重复条目?

谢谢!

1 个答案:

答案 0 :(得分:0)

根据您的评论,我们可以堆叠每个文件,然后从&#34; long&#34;转换结果数据框。到&#34;宽&#34;格式:

library(dplyr)
library(readr)
library(reshape2)

df = lapply(file_list, function(file) {
             dat = read_csv(file)
             dat$source.file = file
             return(dat) 
      })
df = bind_rows(df)
df = dcast(df, id + name ~ source.file, value.var="value")

在上面的代码中,在读取每个文件后,我们添加一个包含文件名(或其修改版本)的新列source.file。*然后我们使用dcast来转换数据框来自&#34; long&#34;到&#34;宽&#34;格式为每个文件中的value创建一个单独的列,每个新列采用我们刚刚在source.file中创建的名称之一。

另请注意,根据您计划对此数据框执行的操作,您可能会发现将其保留为长格式(即跳过dcast步骤)进行进一步分析会更方便。

附录:处理Aggregation function missing: defaulting to length警告。如果您有多个行具有相同的idnamesource.file,则会发生这种情况。这意味着有多个value必须映射到同一个单元格,从而导致聚合。默认聚合函数是length(即,该单元格中值的数量)。我所知道的唯一解决方法是(a)以长格式保存数据,(b)使用不同的聚合函数(例如mean),或(c)添加额外的counter用于区分具有idnamesource.file的相同组合的多个值的案例的列。我们在下面演示这些。

首先,让我们创建一些假数据:

df = data.frame(id=rep(1:2,2), 
                name=rep(c("A","B"), 2), 
                source.file=rep(c("001","002"), each=2),
                value=11:14)

df
  id name source.file value
1  1    A         001    11
2  2    B         001    12
3  1    A         002    13
4  2    B         002    14
  1. idnamesource.file的每个组合只有一个值,因此dcast可以正常工作。

    dcast(df, id + name ~ source.file, value.var="value")
    
      id name 001 002
    1  1    A  11  13
    2  2    B  12  14
    
  2. 使用相同的idnamesource.file添加其他行。由于现在有两个value映射到单个单元格,dcast必须聚合。默认聚合函数是提供值的计数。

    df = rbind(df, data.frame(id=1, name="A", source.file="002", value=50))
    
    dcast(df, id + name ~ source.file, value.var="value")
    
    Aggregation function missing: defaulting to length
    
      id name 001 002
    1  1    A   1   2
    2  2    B   1   1
    
  3. 而是使用mean作为汇总功能。

    dcast(df, id + name ~ source.file, value.var="value", fun.aggregate=mean)
    
      id name 001  002
    1  1    A  11 31.5
    2  2    B  12 14.0
    
  4. 添加新的counter列,以区分多个行具有相同idnamesource.file的情况,并将其包括在内dcast。这会让我们回到每个单元格的单个值,但代价是为某些source.file设置了多个列。

    # Add counter column
    df = df %>% group_by(id, name, source.file) %>%
      mutate(counter=1:n()) 
    

    正如您所看到的,counter值只有idname和{{1}的一种组合时,其值才为1 },但是对于一种情况,其值为1和2,其中有两行具有相同的source.fileidname(下面的第3行和第5行)。

    source.file
    df
    

    现在我们 id name source.file value counter 1 1 A 001 11 1 2 2 B 001 12 1 3 1 A 002 13 1 4 2 B 002 14 1 5 1 A 002 50 2 包含dcast,因此我们为counter&#34; 002&#34;提供了两列。

    source.file
      dcast(df, id + name ~ source.file + counter, value.var="value") 
    
  5. *我不确定您的文件名是什么样的,因此您可能需要调整此项创建一个具有唯一文件标识符的命名格式。例如,如果您的文件名遵循&#34; file001.csv&#34;,&#34; file002.csv&#34;等模式,则可以执行以下操作: id name 001_1 002_1 002_2 1 1 A 11 13 50 2 2 B 12 14 NA