У меня есть три фрейма данных:
Кадр данных 1
chr start end Id chr1 1 400 SN_1 chr1 401 800 SN_2 chr1 801 1200 SN_3 chr1 1201 1600 SN_4 chr1 1601 2000 SN_5 chr1 2001 2400 SN_6 chr1 2401 2800 SN_7
Кадр данных 2
chr start end Id chr1 401 800 SN_2 chr1 801 1200 SN_3 chr1 1201 1600 SN_4
Кадр данных 3
chr start end Id chr1 1201 1600 SN_4 chr1 1601 2000 SN_5 chr1 2001 2400 SN_6
и я хотел бы получить окончательный фрейм данных, где в соответствии с 4-м столбцом 1-го фрейма данных будет сообщено о совпадении или несовпадении по отношению к 4-му столбцу 2-го и 3-го фреймов данных. В новом фрейме данных, если совпадение присутствует, будет сообщен тот же Id, но в случае, если совпадение будет присутствовать, имя Id будет заменено на NA. Может быть, просто запись ввода и вывода будет проще для понимания. Что-то вроде этого:
Желаемый результат:
chr start end Id Id Id chr1 1 400 SN_1 NA NA chr1 401 800 SN_2 SN_2 NA chr1 801 1200 SN_3 SN_3 NA chr1 1201 1600 SN_4 SN_4 SN_4 chr1 1601 2000 SN_5 NA SN_5 chr1 2001 2400 SN_6 NA SN_6 chr1 2401 2800 SN_7 NA NA
Я пробовал с join в команде unix, но не могу сравнить фрейм данных разного размера. Любая идея будет действительно оценена.
решение1
awkрешение:
awk 'FILENAME == ARGV[1] && NR>1{ df2[$2,$3,$4] }
FILENAME == ARGV[2] && FNR>1{ df3[$2,$3,$4] }
FILENAME == ARGV[3]{ if(FNR == 1) { printf("%s\t%s\t%s\n",$0,$NF,$NF) }
else { printf("%s\t%s\t%s\n",$0, (($2,$3,$4) in df2)? $NF :"NA",(($2,$3,$4) in df3)? $NF :"NA")}
}' df2 df3 df1 | column -t
Выход:
chr start end Id Id Id
chr1 1 400 SN_1 NA NA
chr1 401 800 SN_2 SN_2 NA
chr1 801 1200 SN_3 SN_3 NA
chr1 1201 1600 SN_4 SN_4 SN_4
chr1 1601 2000 SN_5 NA SN_5
chr1 2001 2400 SN_6 NA SN_6
chr1 2401 2800 SN_7 NA NA
df2
,df3
иdf1
ваши 2-й, 3-й и 1-йдатафреймфайлы соответственноFILENAME
- встроенная переменная, указывающая на имя текущего обрабатываемого файлаARGV
- встроенная переменная, указывающая на все аргументы, переданные скрипту awk. ieARGV[1]
содержитdf2
FILENAME == ARGV[1] && NR>1
- встречаем 1-й файл (т.е.df2
), начиная со 2-й строкиdf2[$2,$3,$4]
- захват важнейших ценностей из "Кадр данных 2"как ключ массиваdf2
FILENAME == ARGV[2] && FNR>1
- встречаем 2-й файл (т.е.df3
), начиная со 2-й строкиdf3[$2,$3,$4]
- захват важнейших ценностей из "Кадр данных 3"как ключ массиваdf3
FILENAME == ARGV[3]
- столкнувшись с 3-м файлом (т.е.df1
), главныйКадр данных
решение2
perl -lane '$,="\t";
!@ARGV and $. == 1 and print($_, qw/Id/x2),next;
$h{$F[1],$F[2]}->[@ARGV] = $F[3];
!@ARGV and print $_, map { $h{$F[1],$F[2]}->[$_] // q/NA/ } 1..2;
$. = 0 if eof;
' file3 file2 file1
Полученные результаты
chr start end Id Id Id
chr1 1 400 SN_1 NA NA
chr1 401 800 SN_2 SN_2 NA
chr1 801 1200 SN_3 SN_3 NA
chr1 1201 1600 SN_4 SN_4 SN_4
chr1 1601 2000 SN_5 NA SN_5
chr1 2001 2400 SN_6 NA SN_6
chr1 2401 2800 SN_7 NA NA
Выработки
- Порядок входных данных: dataframe3, dataframe2 и dataframe1.
- Предположим, что в dataframe1 заполнены все 4-е столбцы, то есть, нет ни одного пропущенного столбца.
- Вызываем
Perl
в режиме чтения строки+авторазделения:perl -lane
- Во время чтения 3-го кадра @ARGV содержит 2 элемента, во время чтения 2-го кадра — 1 элемент, а во время чтения 3-го кадра — 0 элементов.
- Мы заполняем хеш,
%h
ключами которого являются 2-е и 3-е поля,$F[1],$F[2]
а значениями — анонимные ссылки на массив, поэтому он называется:$h{...}[...]
. - В течение времени 1-го кадра данных (@ARGV, имеющий 0 элементов) мы печатаем каждую строку с содержимым 1-го кадра данных и определяем, существуют ли элементы массива для 2-го/3-го кадров для соответствующих текущих 2-го/3-го полей.