Eu tenho dois arquivos grandes, o primeiro arquivo contém alguns intervalos com 85K linhas:
head data.intervals
id id_uniq numberA numberB
1 g1 5 20
1 g2 6 29
1 g3 17 35
1 g4 37 46
1 g5 50 63
1 g6 70 95
1 g7 87 93
2 g8 3 15
2 g9 10 33
2 g10 60 77
2 g11 90 132
o segundo arquivo contém algumas posições com mais de 2 milhões de linhas:
head data.posiitons
id number
1 4
1 19
1 36
1 49
1 90
2 1
2 20
2 89
2 93
2 120
O que eu quero fazer é o seguinte: Para cada valor na coluna "number" do arquivo de posição, pesquise se é igual ou entre QUALQUER dos valores do par "numberA" e "numberB" do arquivo data.intervals.
Além disso, para esses valores de par "numberA" e "numberB", seu respectivo "id" deve corresponder ao "id" em data.position. Se tudo isso for verdade, quero inserir o respectivo "id.uniq" na coluna data.intervals da respectiva linha no arquivo data.posiitons.
Há outro problema aqui também: alguns desses intervalos se sobrepõem e uma posição pode estar dentro do intervalo de 2 ou mais de 2 intervalos. Quero atribuí-los a cada intervalo separadamente.
aqui está a saída final que desejo obter (NA significa que a posição não está dentro do intervalo de nenhum intervalo):
id number assigned1
1 4 NA
1 19 g1,g2,g3
1 36 NA
1 49 NA
1 90 g6,g7
2 1 NA
2 20 g9
2 89 NA
2 93 g11
2 120 g11
existe alguma solução para fazer essa tarefa com um script bash ou perl?
Você poderia fazer isso com
Perl
usando o seguinte método:Resultado:
Funciona:
%order
hash armazena a ordem em que os IDs exclusivos foram encontrados para fins de reprodução na mesma ordem. OTW, a ordenação do hash é aleatória.grep
deve selecionar os IDs exclusivos que satisfaçam a restrição para o número estar no intervalo. Caso contrário, a"NA"
é passado.Este é o tipo de coisa para a qual você pode considerar usar um pequeno banco de dados - usando, por exemplo
csvsql
, o csvkit (que também fornece umcsvformat
utilitário útil).Por exemplo, supondo que seus dados estejam em arquivos separados por tabulação chamados
intervals
epositions
, e usando o padrãosqlite
, e usando o dialetoÉ um pouco mais complicado obter as
N/A
entradas também: para isso, você pode juntar apositions
tabela original com os resultados e procurarNULL
os valores doassigned1
campo:Assumindo que ambos os arquivos foram ordenados usando
sort -b
, você pode compor todas as combinações possíveis de cada linha nos dois arquivos que possuem o mesmo ID comPara simplificar, também estou ignorando o fato de que os arquivos têm cabeçalhos (considere removê-los).
Isso produziria, para os dados fornecidos,
Aqui você tem o ID, o "ID exclusivo", os dois valores do intervalo e a posição que deseja testar.
Isso pode ser analisado por um
awk
programa:Isso acompanharia os IDs vistos e a posição como chaves em uma
count
matriz. O valor conteria o número de vezes que uma posição foi colocada em um intervalo. Precisamos disso para poder dizer "esta posição não foi encontrada em nenhum intervalo".Se a linha atual na saída de
join
contiver uma posição no 5º campo que esteja dentro do intervalo dos campos 3 e 4, essa contagem será incrementada (e a linha será emitida).Isso gera todas as linhas na saída
join
que correspondem às posições dentro dos intervalos. OEND
bloco trata posições não correspondidas fazendo um loop sobre ocount
array e imprimindo as informações que você solicitou na pergunta, no formato que você solicitou lá sempre que ocount
valor for zero.Para os dados fornecidos, isso produz
Para recolher esses dados com base no "ID exclusivo", poderíamos passá-los por outro
awk
programa. (Estou evitando salvar tudo em uma matriz no mesmoawk
programa, pois pode haver muitos dados).Isso passa por qualquer linha cuja última coluna esteja,
NA
pois elas já estão no formato correto. Em seguida, ele constrói uma "chave" do ID e da posição. Se esta chave for a mesma da linha anterior, o "ID exclusivo" é adicionado a uma string chamadagroup
com uma vírgula como delimitador.Se a chave não for a mesma que a anterior, então encontramos um novo conjunto de correspondências de posição de ID e devemos gerar os dados para o grupo que acabamos de analisar. Isso é feito novamente no
END
bloco de saída dos dados para o último grupo.Juntando tudo isso e lembrando que ambos os arquivos de entrada precisam ser classificados, acabamos com
A saída disso é
que, fora o pedido, é idêntico ao que você esperava. Para corrigir a ordenação, passe isso por
sort -k1,1n -k2,2n
.