Eu tenho uma lista de dados, como
12345
23456
67891
-20000
200
600
20
...
Suponha que o tamanho desse conjunto de dados (ou seja, linhas de arquivo) seja N
. Eu quero desenhar m
linhas aleatoriamente deste arquivo de dados. Portanto, a saída deve ser dois arquivos, um é o arquivo que inclui essas m
linhas de dados e o outro inclui N-m
linhas de dados.
Existe uma maneira de fazer isso usando um comando Linux?
linux
shell
text-processing
user288609
fonte
fonte
Respostas:
Pode não ser a maneira mais eficiente, mas funciona:
Com
$m
contendo o número de linhas.fonte
sort -R
cuida da aleatoriedade. Não tenho certeza se você rebaixou a resposta para isso, mas procure na página de manual primeiro.sort -R
não classifica exatamente sua entrada aleatoriamente: agrupa linhas idênticas. Portanto, se a entrada é, por exemplofoo
,foo
,bar
,bar
e m = 2, em seguida, um ficheiro irá conter ambosfoo
s e o outro irá conter ambasbar
s. O coreutils GNU também possuishuf
, que randomiza as linhas de entrada. Além disso, você não precisa de um arquivo temporário .shuf <file> |head -n $m
?Esse script bash / awk escolhe linhas aleatoriamente e mantém a sequência original nos dois arquivos de saída.
Saída, com base nos dados da pergunta.
fonte
Como em todas as coisas do Unix, existe um utilitário para essa TM .
Programa do dia:
split
split
dividirá um arquivo de várias maneiras,-b
bytes,-l
linhas,-n
número de arquivos de saída. Nós estaremos usando a-l
opção Como você deseja escolher linhas aleatórias e não apenas a primeiram
,sort
o arquivo será aleatoriamente primeiro. Se você quiser ler sobresort
, consulte a minha resposta aqui .Agora, o código real. É bem simples, na verdade:
Isso criará dois arquivos, um com
m
linhas e outro comN-m
linhas, nomeadooutput_prefixaa
eoutput_prefixab
. Certifique-se de quem
é o arquivo maior que você deseja ou obterá vários arquivos de comprimentom
(e um comN % m
).Se você deseja garantir o uso do tamanho correto, aqui está um pequeno código para fazer isso:
Edit: Chegou ao meu conhecimento que algumas
sort
implementações não têm uma-R
bandeira. Se você tiverperl
, você pode substituirperl -e 'use List::Util qw/shuffle/; print shuffle <>;'
.fonte
sort -R
parece estar apenas em algumas versões do tipo (provavelmente a versão gnu). Para outras plataformas, escrevi uma ferramenta chamada 'randline' que não faz nada além de randomizar stdin. Está em beesbuzz.biz/code para quem precisa. (I tendem a embaralhar o conteúdo do arquivo bastante.)sort -R
não classifica exatamente sua entrada aleatoriamente: agrupa linhas idênticas. Portanto, se a entrada é, por exemplofoo
,foo
,bar
,bar
e m = 2, em seguida, um ficheiro irá conter ambosfoo
s e o outro irá conter ambasbar
s. O coreutils GNU também possuishuf
, que randomiza as linhas de entrada. Além disso, você pode escolher os nomes dos arquivos de saída usandohead
e emtail
vez desplit
.Se você não se importa de reordenar as linhas e tiver o GNU coreutils (por exemplo, no Linux ou Cygwin não incorporado, não muito antigo desde que
shuf
apareceu na versão 6.0),shuf
("shuffle") reordena as linhas de um arquivo aleatoriamente. Assim, você pode embaralhar o arquivo e despachar as primeiras m linhas em um arquivo e o restante em outro.Não existe uma maneira ideal de fazer esse envio. Você não pode simplesmente encadear
head
etail
porquehead
ficaria mais à frente. Você pode usarsplit
, mas não tem flexibilidade com relação aos nomes dos arquivos de saída. Você pode usarawk
, é claro:Você pode usar
sed
, o que é obscuro, mas possivelmente mais rápido, para arquivos grandes.Ou você pode usar
tee
para duplicar os dados, se sua plataforma tiver/dev/fd
; tudo bem se m for pequeno:Portably, você pode usar o awk para despachar cada linha por vez. Observe que o awk não é muito bom em inicializar seu gerador de números aleatórios; a aleatoriedade não é apenas definitivamente não adequada para criptografia, mas nem muito boa para simulações numéricas. A semente será a mesma para todas as invocações do awk em qualquer sistema dentro de um período de um segundo.
Se você precisar de uma aleatoriedade melhor, poderá fazer o mesmo no Perl, que semeia seu RNG decentemente.
fonte
awk
exemplo:-v N=$(wc -l <file) -v m=4
... e só imprime uma linha "aleatória" quando o valor aleatório é menor que$m
, em vez de imprimir$m
linhas aleatórias ... Parece queperl
pode estar fazendo a mesma coisa com rand , mas não conheceperl
bem o suficiente para passar por um erro de compilação: erro de sintaxe na linha -e 7, próximo a ") print"shuf
exemplo.head
cat
combo causa perda de dados no segundo teste 3-4 a seguir ... TESTE 1-2{ for i in {00001..10000} ;do echo $i; done; } | { head -n 5000 >out1; cat >out2; }
.. TESTE 3-4{ for i in {00001..10000} ;do echo $i; done; } >input; cat input | { head -n 5000 >out3; cat >out4; }
... Oswc -l
resultados das saídas do TESTE 1-2 são 5000 5000 (bom), mas para TESTE 3-4 are 5000 4539 (not good) .. O differnece varia de acordo com os tamanhos de arquivo envolvidos ... Aqui está um link para o meu código de testehead
lê adiante; o que lê adiante e não imprime é descartado. Atualizei minha resposta com soluções menos elegantes, mas (tenho certeza) de corretas.Assumindo
m = 7
eN = 21
:Nota: Se você substituir
7
por uma variável como$1
ou$m
, precisará usarseq
, não a{from..to}
notação -que não faz expansão de variável.Ele funciona excluindo linha por linha do arquivo, que fica cada vez menor, de modo que o número da linha, que pode ser removido, precisa ficar cada vez menor.
Isso não deve ser usado para arquivos mais longos e para muitas linhas, pois para cada número, em média, o meio arquivo precisa ser lido para o 1º e todo o arquivo para o 2º código sed .
fonte
including them
apenas as linhas originais - portantoincluding
, nãoconsisting of
e não usandoonly
, mas acho que sua interpretação é o que user288609 significava. Ajustarei meu script de acordo.+1
no lugar errado. Deve serrnd=$((RANDOM%(N-i)+1))
onde N = 21 no seu exemplo. Atualmente, ele causased
uma falha quandornd
é avaliado0
. .. Além disso, ele não se adapta muito bem com toda a reescrita desse arquivo. por exemplo, 123 segundos para extrair 5.000 linhas aleatórias de um arquivo de 10.000 linha vs. 0,03 segundos para um método mais direto ...