gpt4 book ai didi

r - 将不同列的大数据文件合并为一个大文件

转载 作者:行者123 更新时间:2023-12-03 16:43:02 28 4
gpt4 key购买 nike

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

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

例子:

> 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
-可以替换成任何东西,例如 NA .

警告 : 文件太大了,我无法同时将它们全部加载到内存中。

我在 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. Process the headers:

    • read all headers of all input files and extract all column names
    • sort the column names in the order you want
    • create a lookup table which returns the column-name when a field number is given (h[n] -> "name")
  2. process the files: after the headers, you can reprocess the files

    • read the header of the file
    • create a lookup table which returns the field number when given a column name. An associative array is useful here: (a["name"] -> field_number)
    • process the remainder of the file

      1. loop over all fields of the merged file
      2. get the column name with h
      3. check if the column name is in a, if not print -, if so print the field number corresponding with a.


这可以使用 GNU awk 轻松完成,使用扩展 nextfileasorti . 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 代码来支持我们的需求。

关于r - 将不同列的大数据文件合并为一个大文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56563626/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com