правильно объединить два файла на основе 2 столбцов в общем
у меня есть два файла, которые я пытаюсь объединить / объединить на основе столбцов 1
и 2
. Они выглядят примерно так, с file1
(58210
строк), будучи намного короче, чем file2
(815530
lines), и я хотел бы найти пересечение этих двух файлов на основе полей 1
и 2
в качестве индекса:
file1
:
2L 25753 33158
2L 28813 33158
2L 31003 33158
2L 31077 33161
2L 31279 33161
3L 32124 45339
3L 33256 45339
...
file2
:
2L 20242 0.5 0.307692307692308
2L 22141 0.32258064516129 0.692307692307692
2L 24439 0.413793103448276 0.625
2L 24710 0.371428571428571 0.631578947368421
2L 25753 0.967741935483871 0.869565217391304
2L 28813 0.181818181818182 0.692307692307692
2L 31003 0.36 0.666666666666667
2L 31077 0.611111111111111 0.931034482758621
2L 31279 0.75 1
3L 32124 0.558823529411765 0.857142857142857
3L 33256 0.769230769230769 0.90625
...
я использовал следующие несколько команд, но в конечном итоге с разными номерами строки:
awk 'FNR==NR{a[]=;next} {if( in a) print}' file1 file2 | wc -l
awk 'FNR==NR{a[]=;next} {if( in a) print}' file2 file1 | wc -l
я не уверен, почему это происходит, и я попытался сортировать до сравнения, на всякий случай у меня есть дубликаты строк (на основе столбцов 1
и 2
) в любом из файлов, но это, похоже, не помогает. (Любые идеи о том, почему это так, также ценятся)
как я могу просто объединить файлы, чтобы только строки file2
, которые имеют соответствующие столбцы 1
и 2
на file1
получить печать, с колонкой 3
of file1
добавлено, чтобы выглядеть примерно так:
2L 25753 0.967741935483871 0.869565217391304 33158
2L 28813 0.181818181818182 0.692307692307692 33158
2L 31003 0.36 0.666666666666667 33158
2L 31077 0.611111111111111 0.931034482758621 33161
2L 31279 0.75 1 33161
3L 32124 0.558823529411765 0.857142857142857 45339
3L 33256 0.769230769230769 0.90625 45339
3 ответов
awk 'NR==FNR{a[,]=;next} (,) in a{print , a[,]}' file1 file2
посмотреть:
$ cat file1
2L 5753 33158
2L 8813 33158
2L 7885 33159
2L 1279 33159
2L 5095 33158
$
$ cat file2
2L 8813 0.6 1.2
2L 5762 0.4 0.5
2L 1279 0.5 0.9
$
$ awk 'NR==FNR{a[,]=;next} (,) in a{print , a[,]}' file1 file2
2L 8813 0.6 1.2 33158
2L 1279 0.5 0.9 33159
$
Если это не то, что вы хотите, уточните и, возможно, опубликуйте более репрезентативный образец ввода/вывода.
прокомментировал версию вышеуказанного кода, чтобы предоставить запрошенное объяснение:
awk ' # START SCRIPT
# IF the number of records read so far across all files is equal
# to the number of records read so far in the current file, a
# condition which can only be true for the first file read, THEN
NR==FNR {
# populate array "a" such that the value indexed by the first
# 2 fields from this record in file1 is the value of the third
# field from the first file.
a[,]=
# Move on to the next record so we don't do any processing intended
# for records from the second file. This is like an "else" for the
# NR==FNR condition.
next
} # END THEN
# We only reach this part of the code if the above condition is false,
# i.e. if the current record is from file2, not from file1.
# IF the array index constructed from the first 2 fields of the current
# record exist in array a, as would occur if these same values existed
# in file1, THEN
(,) in a {
# print the current record from file2 followed by the value from file1
# that occurred at field 3 of the record that had the same values for
# field 1 and field 2 in file1 as the current record from file2.
print , a[,]
} # END THEN
' file1 file2 # END SCRIPT
надеюсь, что это поможет.
если вы хотите присоединиться к файлам строка за строкой, используйте эту команду:
join -o 1.2,1.3,2.4,2.5,1.4 <(cat -n file1) <(cat -n file2)
как вы обновили вопрос:
join -o 1.1,2.2,2.3,1.2 <(sed 's/[[:space:]]\+/@/' file1|sort) \
<(sed 's/[[:space:]]\+/@/' file2|sort)|sed 's/@/\t/'
сначала замените первый разделитель в каждой строке некоторым символом без пробела и отсортируйте оба входных файла. Тогда используйте join
чтобы сделать фактическое присоединение. Отфильтруйте его выход, чтобы заменить непространственный символ пространством.
это вывод из файлов, как в вопросе:
xyz]$ join -o 1.1,2.2,2.3,1.2 <(sed 's/[[:space:]]\+/@/' file1|sort) \
<(sed 's/[[:space:]]\+/@/' file2|sort)|sed 's/@/\t/'
2L 25753 0.967741935483871 0.869565217391304 33158
2L 28813 0.181818181818182 0.692307692307692 33158
2L 31003 0.36 0.666666666666667 33158
2L 31077 0.611111111111111 0.931034482758621 33161
2L 31279 0.75 1 33161
3L 32124 0.558823529411765 0.857142857142857 45339
3L 33256 0.769230769230769 0.90625 45339
можно использовать join
команда, но вам нужно создать одно поле соединения в каждой таблице данных. Предполагая, что у вас есть другие значения, которые 2L
в столбце 1 этот код должен работать независимо от отсортированного или несортированного характера двух входных файлов:
tmp=${TMPDIR:-/tmp}/tmp.$$
trap "rm -f $tmp.?; exit 1" 0 1 2 3 13 15
awk '{print ":" , }' file1 | sort > $tmp.1
awk '{print ":" , }' file2 | sort > $tmp.2
join -o 2.2,2.3,2.4,2.5,1.4 $tmp.1 $tmp.2
rm -f $tmp.?
trap 0
если у вас bash
и "замена процесса", или если вы знаете, что данные уже отсортированы соответствующим образом, вы можете упростить обработку.
Я не совсем уверен, почему ваш код не работал, но я, вероятно, буду использовать a[,]
для индексов; это даст вам меньше проблем, если некоторые из ваших значений столбца 1 являются чисто числовыми и поэтому могут быть смущены, когда вы объединяете столбцы 1 и 2. Вот почему' key creation'awk
скрипты использовали двоеточие между полями.
с пересмотренными файлами данных, как показано:
file1
2L 5753 33158
2L 8813 33158
2L 7885 33158
2L 7885 33159
2L 1279 33158
2L 5095 33158
2L 3256 33158
2L 5372 33158
2L 7088 33161
2L 5762 33161
file2
2L 5095 0.666666666666667 1
2L 5372 0.5 0.925925925925926
2L 5762 0.434782608695652 0.580645161290323
2L 5904 0.571428571428571 0.869565217391304
2L 5974 0.434782608695652 0.694444444444444
2L 6353 0.785714285714286 0.84
2L 7088 0.590909090909091 0.733333333333333
2L 7885 0.714285714285714 0.864864864864865
2L 7902 0.642857142857143 0.810810810810811
2L 8263 0.833333333333333 0.787878787878788
(без изменений по сравнению с вопрос.)
выход
2L 5095 0.666666666666667 1 33158
2L 5372 0.5 0.925925925925926 33158
2L 5762 0.434782608695652 0.580645161290323 33161
2L 7088 0.590909090909091 0.733333333333333 33161
2L 7885 0.714285714285714 0.864864864864865 33158
2L 7885 0.714285714285714 0.864864864864865 33159