linux - 是否有任何命令可以在 Linux 中基于多列进行模糊匹配
问题描述
我有两个 csv 文件。文件 1
D,FNAME,MNAME,LNAME,GENDER,DOB,snapshot
2,66M,J,Rock,F,1995,201211.0
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
文件 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。因为File 1的观察中对应的信息不完整,所以我正在考虑使用模糊匹配尽可能多的回退他们的PID(当然要考虑电平精度)。例如,文件 1 中 FNAME "Paul" 和 LNAME "Row" 的观测值应分配相同的 PID,因为文件 2 中只有一个类似的观测值。但对于 FNAME "Marc" 和 LNAME "Robert" 的观测值,Marc,MS,Robert,M,2000,201211.0
应分配 PID“S1”、Marc,H,Robert,M,2000,201211.0
PID“S0”和Marc,M,Robert,M,,201211.0
“S0”或“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、GENDER 使用模糊匹配来回退文件 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 的观察顺序,所以它必须是一种左连接。因为我的原始数据大小约为 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
}
}
输出:
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
这里的“模糊匹配”是幼稚的if($i~j || j~$i)
,但可以随意用任何近似匹配算法替换它,例如互联网上有一些 Levenshtein 距离算法的实现。罗塞塔似乎有一个。
您没有提到有多大file2
,但如果它超出了您的内存容量,您可能需要考虑以某种方式拆分文件。
更新:将字段映射file1
到file2
字段的版本(如评论中所述):
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
}
}
推荐阅读
- java - Spring RestTemplate 在尝试反序列化对象的嵌套列表时返回空对象
- ios - 仅在通过 ssh 运行时,Fastlane gym 失败并出现错误:Task failed with exit 1 signal 0 /usr/bin/codesign --force sign '' '--verbose'
- android - JavaScript 接口注入漏洞修复
- python-3.x - 如何解决错误:UnicodeDecodeError:'utf-8'?
- python - 在 Tkinter 的 for 循环中创建暂停
- php - 将注册表单数据提交到数据库 - phpMyAdmin
- r - Web API - 如何在 R 中选择 httr::get() 请求中感兴趣的变量
- sql - 带有 INSERT 的 Oracle SQL 事务
- angular - 当我单击不同组件的按钮时,在不同组件的角度显示模式中?
- python - keras 序列模型中的多个输出