Есть ли какая-либо команда для нечеткого сопоставления в Linux, основанная на нескольких столбцах - PullRequest
0 голосов
/ 06 октября 2019

У меня есть два 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, для возврата PID этих наблюдений в Файл 1 на основе столбцовFNAME, MNAME, LNAME, GENDER и DOB. Поскольку соответствующая информация в наблюдениях за файлом 1 не является полной, я думаю об использовании нечеткого сопоставления для получения как можно большего числа их PID (конечно, точность уровня должна приниматься во внимание). Например, наблюдения с FNAME "Paul" и LNAME "Row" в файле 1 должны иметь один и тот же 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".

Поскольку я хочу компенсировать PID файла 1 как можно больше при сохранении высокой точности, я рассмотрю три шага. Во-первых, используйте команду, чтобы убедиться, что если и только если эти данные в 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, чтобы отменить PID наблюдений файла 1, который являетсяне определены на первом этапе. Таким образом, предполагается, что выходные данные этих двух шагов будут

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, так что это должно быть своего рода соединение слева. Поскольку мой исходный размер данных составляет около 100 ГБ, я хочу использовать Linux для решения моей проблемы. Но я понятия не имею, как выполнить последние два шага через awk или любую другую команду в Linux. Есть ли кто-нибудь, кто может оказать мне услугу? Спасибо.

1 Ответ

0 голосов
/ 06 октября 2019

Вот пример с 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), но не стесняйтесь заменить его любым приближенным алгоритмом сопоставления, например, есть несколькореализации алгоритмов расстояния Левенштейна, плавающих в интернете. У Розетты, кажется, есть один.

Вы не упомянули, насколько велик 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
    }
}
...