Em R, tenho o seguinte dataframe com a coluna "overlap" listando linhas que têm valores sobrepostos em alguma outra coluna.
df <- data.frame(overlap = c("1,2,3", "1,2,3", "1,2,3,4", "3,4",
"5,6", "5,6,7", "6,7",
"8,9", "8,9,10", "9,10",
"11,12,13", "11,12,13",
"11,12,13,14", "13,14",
"15,16", "15,16,17", "16,17",
"18,19", "18,19,20", "19,20"))
df
overlap
1 1,2,3
2 1,2,3
3 1,2,3,4
4 3,4
5 5,6
6 5,6,7
7 6,7
8 8,9
9 8,9,10
10 9,10
11 11,12,13
12 11,12,13
13 11,12,13,14
14 13,14
15 15,16
16 15,16,17
17 16,17
18 18,19
19 18,19,20
20 19,20
Gostaria de identificar linhas com valores comuns, mesmo que esses valores não estejam em todas as linhas, e então manter apenas 1 das linhas. Por exemplo, as linhas 1-4 contêm o conjunto combinado 1,2,3,4 e eu gostaria de manter apenas uma dessas linhas. Se mantivermos a primeira linha, o df resultante seria:
1 1,2,3
5 5,6
8 8,9
11 11,12,13
15 15,16
18 18,19
Pesquisei muitas outras soluções aqui e nenhuma inclui comprimentos de linhas desiguais, o que é vital, pois os dados completos podem ter linhas com dezenas de valores.
Uma opção para esses dados de exemplo específicos é criar um
igraph
gráfico a partir de sobreposições de linhas, detectar componentes conectados no gráfico resultante e usar o cluster id do componente como uma variável de agrupamento. A partir daí, podemos escolher a primeira linha de cada grupo.Gráfico de sobreposições para referência:
Podemos tentar
{ivs}
:dando
Isso
vapply
é um pouco redundante, pois chamamosas.numeric
várias vezes. Você realmente quer inteiros separados por vírgula armazenados como caractere?dando
Editar
@Chris está certo no comentário abaixo. Eu deveria acrescentar alguma explicação.
(1) Reestruture os dados. Divida as strings, encontre o primeiro e o último valor, coaja
character
paranumeric
.dá
Isso obviamente assume que o menor inteiro está na primeira posição e o maior na última -- uma suposição razoável? Caso contrário, deveríamos forçar para numérico primeiro e aplicar
range
em cada elemento da lista.(2) Para criar vetores de intervalo , usamos . De sua documentação (cp. ):
iv()
help(iv)
ou seja
Por fim, usamos
iv_groups
. Dehelp(iv_groups)
:(3) Parece que a saída desejada é um vetor de caracteres, onde todas as sequências inteiras dos intervalos restantes são coladas juntas.
Para conseguir isso, usamos
ivs::iv_start()
eivs::iv_end()
para acessar os limites de cada intervalo. Agora gostaríamos de gerar sequências regulares. Infelizmente,:
não é vetorizado, por isso introduzimos:toSpring()
é um wrapper paraformat()
, sua página de ajuda afirmaA aplicação de nossa função personalizada a cada início e fim fornece
Observação
Você também pode usar esta versão mais curta.
onde usamos um truque para poder usar o operador de pipe para frente da base.
Aqui está uma
igraph
opçãoSe executarmos um conjunto de dados fictício como abaixo (um pouco diferente do exemplo dos dados do OP, veja o primeiro
overlap
valor)nós obteremos
e os dados originais da pergunta do OP (começando
"1,2,3"
como o primeiro valor) fornecem