Как объединить два файла на основе сопоставления двух столбцов?

33

У меня есть file1 лайки:

0   AFFX-SNP-000541  NA
0   AFFX-SNP-002255  NA
1   rs12103          0.6401
1   rs12103_1247494  0.696
1   rs12142199       0.7672

И файл 2:

0   AFFX-SNP-000541   1
0   AFFX-SNP-002255   1
1   rs12103           0.5596
1   rs12103_1247494   0.5581
1   rs12142199        0.4931

И хотел бы файл3 такой, что:

0   AFFX-SNP-000541     NA       1
0   AFFX-SNP-002255     NA       1
1   rs12103             0.6401   0.5596
1   rs12103_1247494     0.696    0.5581
1   rs12142199          0.7672   0.4931

Что означает поместить 4-й столбец файла2 в файл1 по имени 2-го столбца.

Дадун Чжан
источник
1
Файл2 получил только три столбца?
Бернхард

Ответы:

48

Это должно сделать это:

join -j 2 -o 1.1,1.2,1.3,2.3 file1 file2

Важно : это предполагает, что ваши файлы отсортированы (как в вашем примере) в соответствии с именем SNP. Если нет, сначала отсортируйте их:

join -j 2 -o 1.1,1.2,1.3,2.3 <(sort -k2 file1) <(sort -k2 file2)

Выход:

0 AFFX-SNP-000541 NA 1
0 AFFX-SNP-002255 NA 1
1 rs12103 0.6401 0.5596
1 rs12103_1247494 0.696 0.5581
1 rs12142199 0.7672 0.4931

Пояснение (с info join ):

`join 'записывает в стандартный вывод строку для каждой пары входных строк, имеющих одинаковые поля соединения.

`-1 FIELD'
     Join on field FIELD (a positive integer) of file 1.

`-2 FIELD'
     Join on field FIELD (a positive integer) of file 2.

`-j FIELD'
     Equivalent to `-1 FIELD -2 FIELD'.

`-o FIELD-LIST'

 Otherwise, construct each output line according to the format in
 FIELD-LIST.  Each element in FIELD-LIST is either the single
 character `0' or has the form M.N where the file number, M, is `1'
 or `2' and N is a positive field number.

Таким образом, вышеприведенная команда объединяет файлы во втором поле и печатает 1-е, 2-е и 3-е поля первого файла, за которым следует 3-е поле файла2.

Тердон
источник
16

Вы можете использовать awk:

$ awk 'NR==FNR {h[$2] = $3; next} {print $1,$2,$3,h[$2]}' file2 file1 > file3

выход:

$ cat file3
0 AFFX-SNP-000541 NA 1
0 AFFX-SNP-002255 NA 1
1 rs12103 0.6401 0.5596
1 rs12103_1247494 0.696 0.5581
1 rs12142199 0.7672 0.4931

Объяснение:

Проходить file2( NR==FNRверно только для первого аргумента файла). Сохранить столбец 3 в хэш-массив с использованием колонки 2 в качестве ключа: h[$2] = $3. Затем пройдитесь file1и выведите все три столбца $1,$2,$3, добавив соответствующий сохраненный столбец из хеш-массива h[$2].

grebneke
источник
Большое спасибо. Просто интересно, что означает «h [$ 2] = $ 3»? На самом деле мне нужно точно соответствовать file1 $ 2 == file2 $ 2 в моих сложных случаях (которые не нужны в том же порядке).
Дадун Чжан
1
h[$2] = $3это присвоение хеша. Это сохранить $3как значение и $2как ключ. Пример: h["name"] = "Dadong". Теперь print h["name"]выходы Dadong. Он делает то, что вы хотите, он точно соответствует второму столбцу из обоих файлов.
Гребнеке
6

Если вам не нужно заказывать, то простое решение будет

paste file{1,2} | awk '{print $1,$2,$3,$6}' > file3

Это предполагает, что все строки имеют три записи, и столбцы 1 и 2 обоих файлов одинаковы (как в данных вашего примера)

Бернхард
источник
1
+1 за отличное использованиеpaste
grebneke
1
@grebneke и Bernhard, так как вы, кажется, фанаты, pasteможете ли вы найти способ ответить на это с помощью coreutils?
Тердон
@terdon - скромная попытка: unix.stackexchange.com/a/113909/32165
grebneke
1
@terdon Я бы посоветовал пересмотреть программу, которая выводит этот s ***
Бернхард
Ничего плохого с форматом, отлично прилично разделенных табуляцией файлов. В любом случае, с таким типом данных у вас обычно нет выбора в отношении формата, он получается из другой программы.
Terdon