Como classificar colunas com base na primeira linha?

12

Eu preciso classificar as colunas de um conjunto de dados muito grande (1.000 linhas e 700.000 colunas). Como exemplo, minhas colunas são dispostas aleatoriamente como: col1 col4 col3 col2, e eu preciso classificar isso.

Eu tenho tentado alguns comandos, mas não tenho sucesso.

exemplo:

ID M2 M5 M8 M1 M3 M9 .....M7000000
Animal1 1 0 2 1 0 2 .....1
Animal2 0 1 2 0 1 1 .....0
Animal3 2 1 0 1 2 1 .....0
.
.
.
.
Animaln

Neste exemplo, pontos significa que tenho muitas colunas e linhas. Mais uma vez, preciso classificar as colunas para serem semelhantes:

ID M1 M2 M3 M4 M5 M6 .....M7000000
Animal1 1 0 2 1 0 2 .....1
Animal2 0 1 2 0 1 1 .....0
Animal3 2 1 0 1 2 1 .....0
.
.
.
.
Animaln

Obrigado

    
por LLVerardo 07.06.2017 / 15:17

8 respostas

9

Com o GNU datamash e o GNU sort :

datamash transpose -t ' ' -H <file_in.csv | sort -V | datamash transpose -t ' ' -H >file_out.csv

Isso funciona bem para dados "razoavelmente pequenos". Pode ou não funcionar com o seu arquivo.

Editar: As soluções abaixo sem transposições devem ser menos intensivas em recursos.

    
por 07.06.2017 / 16:20
6
perl -pale '
   $. == 1 and
   @I = map  { $_->[1] }
        sort { $a->[0] <=> $b->[0] }
        map  { [ $F[$_] =~ /^M(\d+)$/, $_ ] } 1..$#F;
   $_ = "@F[0, @I]";
' yourlargefile
  1. Para a primeira linha, classificamos numericamente a segunda ... última coluna usando as porções numéricas após o dígito M que ocorre no início, usando o bem conhecido Schwartzian maneuver . Isso nos dá os índices reordenados para que as colunas saiam na ordem numericamente ordenada (M1, M2, M3, ...)
  2. Tudo o que resta é usar esses índices provenientes de @I para reorganizar os elementos @F .
  3. A atribuição da matriz em um formulário de aspas duplas converte-a em uma string com elementos separados por espaço.
  4. A opção -p para Perl ativa a auto-impressão de $_ de conteúdo, -l deve adicionar newline .
por 07.06.2017 / 16:33
6

Usando o módulo perl Sort :: Naturally

dados de entrada

ID M2 M5 M8 M1 M3 M9 M700000
A1 m1,2 m1,5 m1,8 m1,1 m1,3 m1,9 m1,7000000
A2 m2,2 m2,5 m2,8 m2,1 m2,3 m2,9 m2,7000000
A3 m3,2 m3,5 m3,8 m3,1 m3,3 m3,9 m3,7000000
A1000 m1000,2 m1000,5 m1000,8 m1000,1 m1000,3 m1000,9 m1000,7000000
perl -MSort::Naturally -lane '
  if ($. == 1) {
    @indices = (0, map  { $_->[0] }
                   sort { ncmp($a->[1], $b->[1]) }
                   map  { [$_, $F[$_]] }
                   1..$#F
               );
    $, = " ";
  }
  print @F[@indices]
' test.data

saída

ID M1 M2 M3 M5 M8 M9 M700000
A1 m1,1 m1,2 m1,3 m1,5 m1,8 m1,9 m1,7000000
A2 m2,1 m2,2 m2,3 m2,5 m2,8 m2,9 m2,7000000
A3 m3,1 m3,2 m3,3 m3,5 m3,8 m3,9 m3,7000000
A1000 m1000,1 m1000,2 m1000,3 m1000,5 m1000,8 m1000,9 m1000,7000000
    
por 07.06.2017 / 17:06
4

Se você tiver o rs utility instalado, poderá fazer o seguinte:

rs -c' ' -T | {
    stdbuf -i0 sed "1q"
    sort -V
} | rs -C' ' -T

Ou tudo em uma linha:

rs -c' ' -T | { stdbuf -i0 sed "1q"; sort -V ; } | rs -C' ' -T
  • O primeiro rs transpõe os dados de entrada (com campos espaciais)
  • O grupo de comandos:
    • sed lê a primeira linha, gera a saída e depois sai, deixando o resto do canal de rs intocado. stdbuf é necessário para garantir que sed apenas leia até a primeira nova linha e não mais, desativando o buffer de entrada
    • sort s as linhas restantes
  • O segundo rs transpõe o fluxo resultante de volta ao seu formato original.

rs é instalado por padrão no MacOS. Nos sistemas Linux, você pode ter que instalá-lo - por exemplo,

sudo apt install rs

Ressalva: stdbuf e sort s -V são específicas do GNU, portanto não funcionam em MacOS não modificados.

    
por 07.06.2017 / 21:07
0

Se você tem o GNU awk , você pode tentar isto:

NR == 1 {
    for (i = 2; i <= NF; i++) {
        columns[substr($i, 2)] = i;
    }
    count = asorti(columns, sorted, "@ind_num_asc");
    printf("%s", $1);
    for (i = 1; i <= count; i++) {
        printf(" M%s", sorted[i]);
        indx[i] = columns[sorted[i]];
    }
    print "";
    next;
}
{
    printf("%s", $1);
    for (i = 1; i <= count; i++) {
        printf(" %s", $(indx[i]));
    }
    print "";
}
    
por 08.06.2017 / 11:45
0

Em Python:

from csv import DictReader, DictWriter
with open('in_file.csv') as infile, open('out_file.csv') as outfile:
  reader = DictReader(infile)
  writer = DictReader(outfile, fieldnames=sorted(reader.fieldnames))
  writer.writerows(reader)
    
por 11.06.2017 / 07:42
0

Eu não sei se você considerou isso como uma boa resposta, mas ...

Por que você não usa um banco de dados para resolver esse problema? você pode importar seu conjunto de dados como uma tabela temporária e, em seguida, fazer um

SELECT column1, column2, ... column-n FROM my_temp_table

Você pode usar outros filtros ou transformações conforme necessário. Então, você pode reformatar sua saída conforme necessário.

Todas essas tarefas podem ser programadas como um script bash e encadear saídas usando pipes.

Às vezes eu tenho usado o comando "pv" para ver o progresso da saída entre os comandos.

Para importar o conjunto de dados, você pode programar um ETL usando o Pentaho Data Integration.

    
por 12.06.2017 / 21:02
0

Talvez isso também possa ajudar você.

  1. Primeiro você pode usar transpor seu arquivo (um dos link )
  2. Classifique a primeira coluna com o comando sort.
  3. Transpor novamente.

Ex:

$ echo "ID M2 M5 M8 M1 M3 M9 .....M7000000
Animal1 1 0 2 1 0 2 .....1
Animal2 0 1 2 0 1 1 .....0
Animal3 2 1 0 1 2 1 .....0
.
.
.
.
Animaln" | awk '
{ 
    for (i=1; i<=NF; i++)  {
        a[NR,i] = $i
    }
}
NF>p { p = NF }
END {    
    for(j=1; j<=p; j++) {
        str=a[1,j]
        for(i=2; i<=NR; i++){
            str=str" "a[i,j];
        }
        print str
    }
}' | sort -n | awk '
{ 
    for (i=1; i<=NF; i++)  {
        a[NR,i] = $i
    }
}
NF>p { p = NF }
END {    
    for(j=1; j<=p; j++) {
        str=a[1,j]
        for(i=2; i<=NR; i++){
            str=str" "a[i,j];
        }
        print str
    }
}'
ID M1 M2 M3 M5 .....M7000000 M8 M9
Animal1 1 1 0 0 .....1 2 2
Animal2 0 0 1 1 .....0 2 1
Animal3 1 2 2 1 .....0 0 1
.       
.       
.       
.       
Animaln    
    
por 13.06.2017 / 08:22