将具有不同列的大数据文件合并为一个大文件

2024-03-25

我有 N 个制表符分隔的文件。每个文件都有一个标题行,说明列的名称。有些列是所有文件共有的,但有些列是唯一的。

我想将所有文件合并成一个包含所有相关标头的大文件。

Example:

> cat file1.dat
a b c
5 7 2
3 9 1

> cat file2.dat
a b e f
2 9 8 3
2 8 3 3
1 0 3 2

> cat file3.dat
a c d g
1 1 5 2

> merge file*.dat
a b c d e f g
5 7 2 - - - -
3 9 1 - - - -
2 9 - - 8 3 -
2 8 - - 3 3 -
1 0 - - 3 2 -
1 - 1 5 - - 2

The -可以用任何东西代替,例如NA.

Caveat:文件太大,我无法同时将所有文件加载到内存中。

我在 R 中使用了一个解决方案

write.table(do.call(plyr:::rbind.fill, 
            Map(function(filename) 
                    read.table(filename, header=1, check.names=0), 
                filename=list.files('.'))), 
    'merged.dat', quote=FALSE, sep='\t', row.names=FALSE)

但当数据太大时,会因内存错误而失败。

实现这一目标的最佳方法是什么?

我认为最好的路线是首先循环遍历所有文件以收集列名称,然后循环遍历文件以将它们转换为正确的格式,并在遇到它们时将它们写入光盘。然而,是否已经有一些可用的代码可以执行此操作?


从算法的角度来看,我将采取以下步骤:

  1. 处理标题:

    • 读取所有输入文件的所有标题并提取所有列名
    • 按照您想要的顺序对列名称进行排序
    • 创建一个查找表,当给定字段编号时返回列名(h[n] -> "name")
  2. 处理文件:在标头之后,您可以重新处理文件

    • 读取文件头
    • 创建一个查找表,在给定列名时返回字段编号。关联数组在这里很有用:(a["name"] -> field_number)
    • 处理文件的其余部分

      1. 循环合并文件的所有字段
      2. 获取列名h
      3. 检查列名是否在a,如果不打印-,如果是,则打印对应的字段号a.

这可以通过使用扩展的 GNU awk 轻松完成nextfile and asorti. The nextfile函数允许我们只读取文件头并移动到下一个文件,而不处理整个文件。由于我们需要处理该文件两次(步骤 1 读取文件头,步骤 2 读取文件),因此我们将要求 awk 动态操作其参数列表。每次处理文件头时,我们都会将其添加到参数列表的末尾ARGV所以它可以用于step 2.

BEGIN { s="-" }                # define symbol
BEGIN { f=ARGC-1 }             # get total number of files
f { for (i=1;i<=NF;++i) h[$i]  # read headers in associative array h[key]
    ARGV[ARGC++] = FILENAME    # add file at end of argument list
    if (--f == 0) {            # did we process all headers?
       n=asorti(h)             # sort header into h[idx] = key
       for (i=1;i<=n;++i)      # print header
           printf "%s%s", h[i], (i==n?ORS:OFS)
    }
    nextfile                   # end of processing headers
}           
# Start of processing the files
(FNR==1) { delete a; for(i=1;i<=NF;++i) a[$i]=i; next } # read header
{ for(i=1;i<=n;++i) printf "%s%s", (h[i] in a ? $(a[h[i]]) : s), (i==n?ORS:OFS) }

如果将以上内容存储在文件中merge.awk你可以使用命令:

awk -f merge.awk f1 f2 f3 f4 ... fx

类似的方式,但不那么麻烦f:

BEGIN { s="-" }                 # define symbol
BEGIN {                         # modify argument list from
        c=ARGC;                 #   from: arg1 arg2  ... argx
        ARGV[ARGC++]="f=1"      #   to:   arg1 arg2  ... argx f=1 arg1 arg2  ... argx
        for(i=1;i<c;++i) ARGV[ARGC++]=ARGV[i]
}
!f { for (i=1;i<=NF;++i) h[$i]  # read headers in associative array h[key]
     nextfile
}
(f==1) && (FNR==1) {            # process merged header
     n=asorti(h)                # sort header into h[idx] = key
     for (i=1;i<=n;++i)         # print header
        printf "%s%s", h[i], (i==n?ORS:OFS)
     f=2                         
}
# Start of processing the files
(FNR==1) { delete a; for(i=1;i<=NF;++i) a[$i]=i; next } # read header
{ for(i=1;i<=n;++i) printf "%s%s", (h[i] in a ? $(a[h[i]]) : s), (i==n?ORS:OFS) }

此方法略有不同,但允许将具有不同字段分隔符的文件处理为

awk -f merge.awk f1 FS="," f2 f3 FS="|" f4 ... fx

如果你的参数列表变得太长,你可以使用awk为您创建它:

BEGIN { s="-" }                 # define symbol
BEGIN {                         # read argument list from input file:
  fname=(ARGC==1 ? "-" : ARGV[1])
  ARGC=1                        # from: filelist or /dev/stdin
  while ((getline < fname) > 0) #   to:   arg1 arg2 ... argx
     ARGV[ARGC++]=$0
}
BEGIN {                         # modify argument list from
        c=ARGC;                 #   from: arg1 arg2  ... argx
        ARGV[ARGC++]="f=1"      #   to:   arg1 arg2  ... argx f=1 arg1 arg2  ... argx
        for(i=1;i<c;++i) ARGV[ARGC++]=ARGV[i]
}
!f { for (i=1;i<=NF;++i) h[$i]  # read headers in associative array h[key]
     nextfile
}
(f==1) && (FNR==1) {            # process merged header
     n=asorti(h)                # sort header into h[idx] = key
     for (i=1;i<=n;++i)         # print header
        printf "%s%s", h[i], (i==n?ORS:OFS)
     f=2                         
}
# Start of processing the files
(FNR==1) { delete a; for(i=1;i<=NF;++i) a[$i]=i; next } # read header
{ for(i=1;i<=n;++i) printf "%s%s", (h[i] in a ? $(a[h[i]]) : s), (i==n?ORS:OFS) }

可以运行为:

$ awk -f merge.awk filelist
$ find . | awk -f merge.awk "-"
$ find . | awk -f merge.awk

或任何类似的命令。

正如您所看到的,通过仅添加一小部分代码,我们就能够灵活地调整 awk 代码来支持我们的需求。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将具有不同列的大数据文件合并为一个大文件 的相关文章

  • 在批处理模式下运行 R - 打印到屏幕?

    跑步时 R CMD BATCH options filename r 我想控制输出的打印位置 我可以使用以下命令抑制 Rout 文件的创建 R CMD BATCH options filename r dev null 但是否可以将输出直接
  • 如何绘制两个 ggplot 密度分布之间的差异?

    我想使用 ggplot2 来说明两个相似密度分布之间的差异 这是我拥有的数据类型的玩具示例 library ggplot2 Make toy data n sp lt 100000 n dup lt 50000 D lt data fram
  • 如何从脚本向 sudo 提供密码?

    请注意 这是在我的本地计算机上运行的来宾虚拟机 VBox 我不担心安全性 我正在编写一个将在 Linux Ubuntu VM 上执行的脚本myuser用户 该脚本将在下面创建一个非常大的目录树 etc myapp 目前我必须手动完成所有这些
  • Pandas dataframe ,使用 iloc 替换最后一行

    我正在尝试使用 iloc 替换 Pandas 数据帧的最后一行 但是我无法让它工作 有很多解决方案 但最简单 最慢 的是这里 如何在 Python 中对 Pandas 数据帧上的行进行 FIFO 推送操作 https stackoverfl
  • 更改列名称的字母大小写

    我有大量数据集 每个数据集都包含一长串列名 在某些文件中 列名称全部大写 而在某些文件中 仅列名称的第一个字母大写 我需要附加数据集 并认为匹配数据集中的列名称的最简单方法是将全大写名称转换为仅第一个字母大写的名称 我希望找到一个通用的解决
  • -bash: gulp: 在 Mac 中找不到命令

    我尝试在 mac 中安装 gulp 如下所示 Is iMac itop npm root Users itop node modules Is iMac itop npm config set prefix usr local Is iMa
  • 当我通过 shell 脚本创建 .txt 文件时,为什么文件名末尾出现问号? [复制]

    这个问题在这里已经有答案了 我正在编写一个 shell 脚本 我应该在其中创建 1 个文本文件 当我这样做时 文件名末尾出现一个问号 是什么原因 我正在 bash 脚本中尝试以下方法 1 grep ERROR a1 gt text txt
  • 循环更改多个数据帧

    例如 我有这三个数据集 就我而言 它们更多并且有很多变量 data frame1 lt data frame a c 1 5 3 3 2 b c 3 6 1 5 5 c c 4 4 1 9 2 data frame2 lt data fra
  • 估算缺失数据,同时强制相关系数保持不变

    考虑以下 excel 数据集 m r 2 0 3 3 0 8 4 0 1 3 2 1 5 2 2 3 1 9 2 5 1 2 3 0 2 0 2 6 我的目标是使用以下条件填充缺失值 将上述两列之间的成对相关性表示为 R 大约 0 68 将
  • 使用 Visual Studio 构建 R 包 (C API)

    我正在尝试使用 Visual Studio 构建一个简单的 R 包 这是我的代码 include
  • 从数据帧字典中获取单独的数据帧 Python

    我有一本字典d充满了数据帧的集合 key type size value gm1 dataframe mxn gm2 dataframe mxN gm10 dataframe nxM 我想使用它们来一一输出这些数据帧keys作为新数据框的名
  • rvest open.connection(x, "rb") 中出现错误:已达到超时

    我正在尝试从中抓取内容http google com http google com 错误信息就出来了 library rvest html http google com open connection x rb 中的错误 已达到超时另外
  • 如何在 dplyr 中使用切片来保留 R 中具有 NA 值的行

    我有以下数据集 我想知道每个组的最小单词 如果没有最小单词 它是 NA 我仍然想显示它 df data frame key c A A B B C word c 1 2 3 5 NA df gt group by key gt slice
  • 不使用apply函数对data.table的每一行进行操作的方法

    我在下面写了一个简单的函数 mcs lt function v ifelse sum diff sort v gt 6 gt 0 NA sd v 它应该采用一个向量 对其进行排序 然后检查每个连续差异中是否存在大于 6 的差异 如果差值大于
  • R:使用 RGDAL 和 RASTER 包时抛出错误

    给所有可能相关的人 这是源代码 GRA D1 lt raster files 1 Sets up an empty output raster GRA D1 lt writeStart GRA D1 filename GRA D1 tif
  • R 语言 - 等待用户使用 scan 或 readline 输入

    我试图让用户输入一些关键字进行查询 在我的脚本中我使用了 scan 或 readline 我使用 R 嵌入脚本编辑器 Windows 进行了尝试 但是当我执行代码时 它使用我的下一行脚本作为标准输入 这是我的 部分 脚本 keywords
  • Bash 中 $() 和 () 之间的区别

    当我打字时ls l echo file 支架的输出 这只是简单的回显 被获取并传递到外部ls l命令 就等于简单的ls l file 当我打字时ls l echo file 我们有错误 因为不能嵌套 内部外部命令 有人可以帮助我理解之间的区
  • 将值添加到 rCharts hPlot 工具提示

    我想通过 rCharts 向标准 Highcharts 工具提示添加一些额外的值 示例代码 require rCharts df lt data frame x c 1 5 y c 5 1 z c A B C D E name c K L
  • 按行号和列号对文件进行子集化

    我们想要按行和列对文本文件进行子集化 其中行数和列数是从文件中读取的 不包括标题 第 1 行 和行名称 第 1 列 输入文件 txt制表符分隔的文本文件 header 62 9 3 54 6 1 25 1 2 3 4 5 6 96 1 1
  • 更改 ggplot 条形图填充颜色

    有了这个数据 df lt data frame value c 20 50 90 group c 1 2 3 我可以得到一个条形图 df gt ggplot aes x group y value fill value geom col c

随机推荐