Linux中是否有基于多列的模糊匹配命令

Linux中是否有基于多列的模糊匹配命令,linux,join,awk,levenshtein-distance,Linux,Join,Awk,Levenshtein Distance,我有两个csv文件。 文件1 文件2 PID,FNAME,MNAME,LNAME,GENDER,DOB S2,66M,J,Rock,F,1995 S3,David,HM,Lee,M,1990 S0,Marc,HM,Robert,M,2000 S1,Marc,MS,Robert,M,2000 S6,Paul,,Row,M,2008 S7,Sam,O,Baby,F,2018 我想做的是使用人行横道文件文件2,根据FNAME、MNAME、LNAME、GENDER和DOB列,在文件1中撤销这些观察值的

我有两个csv文件。 文件1

文件2

PID,FNAME,MNAME,LNAME,GENDER,DOB
S2,66M,J,Rock,F,1995
S3,David,HM,Lee,M,1990
S0,Marc,HM,Robert,M,2000
S1,Marc,MS,Robert,M,2000
S6,Paul,,Row,M,2008
S7,Sam,O,Baby,F,2018
我想做的是使用人行横道文件文件2,根据FNAME、MNAME、LNAME、GENDER和DOB列,在文件1中撤销这些观察值的PID。由于文件1中的观测值中的相应信息不完整,我正在考虑使用模糊匹配尽可能多地撤销其PID(当然应该考虑级别精度)。例如,文件1中FNAME“Paul”和LNAME“Row”的观测值应分配相同的PID,因为文件2中只有一个类似的观测值。但对于FNAME“Marc”和LNAME“Robert”的观测值,
Marc,MS,Robert,M,2000201211.0
应分配PID“S1”、
Marc,H,Robert,M,2000201211.0
PID“S0”和
Marc,M,Robert,M,201211.0
或“S1”

<>我想在保持高精度的前提下尽可能多地补偿文件1的PID,我考虑了三个步骤。首先,使用命令确保当且仅当FNAME、MNAME、LNAME、GENDER和DOB中的这些信息都完全匹配时,文件1中的观察值才能分配一个PID。输出应该是

D,FNAME,MNAME,LNAME,GENDER,DOB,snapshot,PID
2,66M,J,Rock,F,1995,201211.0,S2
3,David,HM,Lee,M,,201211.0,
6,66M,,Rock,F,,201211.0,
0,David,H M,Lee,,1990,201211.0,
3,Marc,H,Robert,M,2000,201211.0,
6,Marc,M,Robert,M,,201211.0,
6,Marc,MS,Robert,M,2000,201211.0,
3,David,M,Lee,,1990,201211.0,
5,Paul,ABC,Row,F,2008,201211.0,
3,Paul,ACB,Row,,,201211.0,
4,David,,Lee,,1990,201211.0,
4,66,J,Rock,,1995,201211.0,
接下来,编写另一个命令以确保当DOB信息完全相同时,对FNAME、MNAME、LNAME、SEXT使用模糊匹配,以撤销文件1的观察值的PID,该PID在第一步中未识别。所以这两个步骤的输出应该是

D,FNAME,MNAME,LNAME,GENDER,DOB,snapshot,PID
2,66M,J,Rock,F,1995,201211.0,S2
3,David,HM,Lee,M,,201211.0,
6,66M,,Rock,F,,201211.0,
0,David,H M,Lee,,1990,201211.0,S3
3,Marc,H,Robert,M,2000,201211.0,S0
6,Marc,M,Robert,M,,201211.0,
6,Marc,MS,Robert,M,2000,201211.0,S1
3,David,M,Lee,,1990,201211.0,S3
5,Paul,ABC,Row,F,2008,201211.0,S6
3,Paul,ACB,Row,,,201211.0,
4,David,,Lee,,1990,201211.0,S3
4,66,J,Rock,,1995,201211.0,S2
在最后一步中,使用新命令对所有相关列(即FNAME、MNAME、LNAME、GENDER和DOB)进行模糊匹配,以补偿剩余观测值的PID。因此,最终输出预计为

D,FNAME,MNAME,LNAME,GENDER,DOB,snapshot,PID
2,66M,J,Rock,F,1995,201211.0,S2
3,David,HM,Lee,M,,201211.0,S3
6,66M,,Rock,F,,201211.0,S2
0,David,H M,Lee,,1990,201211.0,S3
3,Marc,H,Robert,M,2000,201211.0,S0
6,Marc,M,Robert,M,,201211.0,S1
6,Marc,MS,Robert,M,2000,201211.0,S1
3,David,M,Lee,,1990,201211.0,S3
5,Paul,ABC,Row,F,2008,201211.0,S6
3,Paul,ACB,Row,,,201211.0,S6
4,David,,Lee,,1990,201211.0,S3
4,66,J,Rock,,1995,201211.0,S2
我需要保持文件1的观察顺序,所以它必须是一种leftouter连接。因为我的原始数据大小约为100Gb,所以我想使用Linux来处理我的问题。
但是我不知道如何通过
awk
或Linux中的任何其他命令来完成最后两个步骤。有人能帮我个忙吗?谢谢。

这里是GNU awk的一个尝试(使用
PROCINFO[“sorted_in”]
选择最合适的候选人)。它对每个字段的
file2
字段值进行散列,并将
PID
附加到值上,如
field[2][“66M”]=“S2”
,并对
file1
中的每个记录计算
PID
匹配的数量,并打印计数最大的记录:

BEGIN {
    FS=OFS=","
    PROCINFO["sorted_in"]="@val_num_desc"
}
NR==FNR {                                                      # file2
    for(i=1;i<=6;i++)                                          # fields 1-6
        if($i!="") {
        field[i][$i]=field[i][$i] (field[i][$i]==""?"":OFS) $1 # attach PID to value
    }
    next
}
{                                                               # file1
        for(i=1;i<=6;i++) {                                     # fields 1-6
            if($i in field[i]) {                                # if value matches
                split(field[i][$i],t,FS)                        # get PIDs
                for(j in t) {                                   # and
                    matches[t[j]]++                             # increase PID counts
                }
            } else {                                            # if no value match
                for(j in field[i])                              # for all field values
                    if($i~j || j~$i)                            # "go fuzzy" :D
                        matches[field[i][j]]+=0.5               # fuzzy is half a match
            }
        }
        for(i in matches) {                                     # the best match first
            print $0,i
            delete matches
            break                                               # we only want the best match
        }
}
这里的“模糊匹配”是naivistic
if($i~j | | j~$i)
,但是可以用任何近似匹配算法来替换它,例如,在互联网上有一些Levenshtein距离算法的实现。罗塞塔似乎有一个

<>你没有提到大的 Fiel2是什么,但是如果它超出了你的内存容量,你可能想考虑以某种方式分割文件。 更新:将
file1
字段映射到
file2
字段的版本(如注释中所述):

开始{
FS=OFS=“,”
PROCINFO[“排序在”]=“val\u num\u desc”
映射[1]=1#将file1字段映射到file2字段
图[2]=3
图[3]=4
map[4]=2
图[5]=5
图[7]=6
}
NR==FNR{#file2

太长了,读不下去了,(我的意思是:1);我的DUP目标是非站点:所以我不能添加它。看看<代码> AdgpP>代码>或代码> TE GalpP<……代码>……如果你刚刚阅读标题,就可以关闭它,但是如果你读了整个问题(我知道,TL;Dr,我几乎跳过它)。我觉得这还不够。我真的很感谢你的帮助。文件2大约有10GB。我是
awk
新手,所以你介意给我解释一下
field[I][$I]=field[I][$I](field[I][$I]==“”?“”:OFS)括号中内容的含义吗$1
?在
split(字段[i][$i],t,FS)
中,
t
FS
表示什么?在最后一个循环
中加上(匹配中的i)…
您如何确保选择最佳匹配项?因为我没有找到最佳匹配项的排序方法。我还有另一个子问题。假设文件1中的字段顺序为
D、MNAME、LNAME、FNAME、GENDER、snapshot、DOB
。那么我该怎么办?嗨,我键入了您的代码,
awk'[yourcode]'file2 file1
在终端中,但它不起作用。终端警告说,
字段[i][$i]=字段[i][$i](字段[i][$i]==“”?“”:OFS)中的方括号格式存在语法错误$1
加上file1循环中的所有括号。您使用的是GNU awk,对吗?脚本具有多维数组,并更改了
travese排序,这两个GNU awk功能。当我输入
awk--help
时,它显示消息
用法:awk[POSIX或GNU样式选项]-f progfile[--]file…用法:awk[POSIX或GNU样式选项][--]“程序”文件…POSIX选项:GNU长选项:….
。awk--version
怎么样?
BEGIN {
    FS=OFS=","
    PROCINFO["sorted_in"]="@val_num_desc"
}
NR==FNR {                                                      # file2
    for(i=1;i<=6;i++)                                          # fields 1-6
        if($i!="") {
        field[i][$i]=field[i][$i] (field[i][$i]==""?"":OFS) $1 # attach PID to value
    }
    next
}
{                                                               # file1
        for(i=1;i<=6;i++) {                                     # fields 1-6
            if($i in field[i]) {                                # if value matches
                split(field[i][$i],t,FS)                        # get PIDs
                for(j in t) {                                   # and
                    matches[t[j]]++                             # increase PID counts
                }
            } else {                                            # if no value match
                for(j in field[i])                              # for all field values
                    if($i~j || j~$i)                            # "go fuzzy" :D
                        matches[field[i][j]]+=0.5               # fuzzy is half a match
            }
        }
        for(i in matches) {                                     # the best match first
            print $0,i
            delete matches
            break                                               # we only want the best match
        }
}
D,FNAME,MNAME,LNAME,GENDER,DOB,snapshot,PID
2,66M,J,Rock,F,1995,201211.0,S2
3,David,HM,Lee,M,,201211.0,S3
6,66M,,Rock,F,,201211.0,S2
0,David,H M,Lee,,1990,201211.0,S3
3,Marc,H,Robert,M,2000,201211.0,S0
6,Marc,M,Robert,M,,201211.0,S1
6,Marc,MS,Robert,M,2000,201211.0,S1
3,David,M,Lee,,1990,201211.0,S3
5,Paul,ABC,Row,F,2008,201211.0,S6
3,Paul,ACB,Row,,,201211.0,S6
4,David,,Lee,,1990,201211.0,S3
4,66,J,Rock,,1995,201211.0,S2
BEGIN {
    FS=OFS=","
    PROCINFO["sorted_in"]="@val_num_desc"
    map[1]=1                                                   # map file1 fields to file2 fields
    map[2]=3
    map[3]=4
    map[4]=2
    map[5]=5
    map[7]=6
}
NR==FNR {                                                      # file2
    for(i=1;i<=6;i++)                                          # fields 1-6
        if($i!="") {
        field[i][$i]=field[i][$i] (field[i][$i]==""?"":OFS) $1 # attach PID to value
    }
    next
}
{                                                              # file1
    for(i in map) {
        if($i in field[map[i]]) {                              # if value matches
            split(field[map[i]][$i],t,FS)                      # get PIDs
            for(j in t) {                                      # and
                matches[t[j]]++                                # increase PID counts
            }
        } else {                                               # if no value match
            for(j in field[map[i]])                            # for all field values
                if($i~j || j~$i)                               # "go fuzzy" :D
                    matches[field[map[i]][j]]+=0.5             # fuzzy is half a match
        }
    }
    for(i in matches) {                                        # the best match first
        print $0,i
        delete matches
        break                                                  # we only want the best match
    }
}