Existe algum comando do Linux que se possa usar para provar um subconjunto de um arquivo? Por exemplo, um arquivo contém um milhão de linhas e queremos amostrar aleatoriamente apenas mil linhas desse arquivo.
Por acaso, quero dizer que cada linha tem a mesma probabilidade de ser escolhida e nenhuma das linhas escolhidas é repetitiva.
head
e tail
pode escolher um subconjunto do arquivo, mas não aleatoriamente. Eu sei que sempre posso escrever um script python para fazer isso, mas me pergunto se existe um comando para esse uso.
command-line
files
command
clwen
fonte
fonte
Respostas:
O
shuf
comando (parte do coreutils) pode fazer isso:E, pelo menos por enquanto, versões não antigas (adicionadas em um commit de 2013 ), que usarão a amostragem de reservatório quando apropriado, o que significa que não deve ficar sem memória e está usando um algoritmo rápido.
fonte
sort
está na mesma seção e claramente não requer entrada classificada.shuf
foi introduzido no coreutils na versão6.0 (2006-08-15)
e, acredite ou não, alguns sistemas razoavelmente comuns (em particular o CentOS 6.5) não possuem essa versão: - |shuf -n
faz amostragem de reservatório, pelo menos quando a entrada é superior a 8K, que é o tamanho que eles determinaram como melhor referência. Veja o código fonte (por exemplo, em github.com/coreutils/coreutils/blob/master/src/shuf.c#L46 ). Desculpe por esta resposta muito tardia. Aparentemente, isso é novo a partir de 6 anos atrás.Se você tiver um arquivo muito grande (que é um motivo comum para obter uma amostra), você encontrará:
shuf
esgota a memória$RANDOM
não funcionará corretamente se o arquivo exceder 32767 linhasSe você não precisar de "exatamente" n linhas de amostra, poderá experimentar uma proporção como esta:
cat input.txt | awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01) print $0}' > sample.txt
Isso usa memória constante , mostra 1% do arquivo (se você souber o número de linhas do arquivo, você pode ajustar esse fator para obter um número próximo de um número limitado de linhas) e funciona com qualquer tamanho de arquivo, mas não retorna um número preciso de linhas, apenas uma proporção estatística.
Nota: O código vem de: https://stackoverflow.com/questions/692312/randomly-pick-lines-from-a-file-without-slurping-it-with-unix
fonte
$RANDOM
não funcionará corretamente para arquivos maiores que 32767 linhas. A declaração "O uso$RANDOM
não atinge o arquivo inteiro" é um pouco ampla.awk
é mais eficiente em termos de recursos do que ashuf
Semelhante à solução probabilística da @ Txangel, mas aproximando-se 100x mais rapidamente.
Se você precisar de alto desempenho, um tamanho exato de amostra e estiver feliz em viver com uma lacuna de amostra no final do arquivo, faça o seguinte (exemplo: 1000 linhas de um arquivo de linha de 1 metro):
.. ou mesmo encadear um segundo método de amostra em vez de
head
.fonte
Caso o
shuf -n
truque em arquivos grandes fique sem memória e você ainda precise de uma amostra de tamanho fixo e um utilitário externo possa ser instalado, tente a amostra :A ressalva é que a amostra (1000 linhas no exemplo) deve caber na memória.
Isenção de responsabilidade: eu sou o autor do software recomendado.
fonte
/usr/local/bin
antes/usr/bin/
, tenha cuidado com o macOS com um amostrador de pilha de chamadas integrado chamadosample
, que faz algo completamente diferente/usr/bin/
.Não estou ciente de nenhum comando único que possa fazer o que você pede, mas aqui está um loop que montei que pode fazer o trabalho:
sed
vai pegar uma linha aleatória em cada um dos 1000 passes. Possivelmente existem soluções mais eficientes.fonte
$RANDOM
possui um intervalo entre 0 e 32767. Portanto, você não obterá um número de linha bem espalhado.Você pode salvar o código a seguir em um arquivo (por exemplo, randextract.sh) e executar como:
---- COMEÇAR ARQUIVO ----
---- END FILE ----
fonte
$RANDOM$RANDOM
não gera números aleatórios em todo o intervalo "0 a 3276732767" (por exemplo, ele gera 1000100000, mas não 1000099999).Se você souber o número de linhas no arquivo (como 1e6 no seu caso), poderá:
Caso contrário, você sempre pode fazer
Isso faria duas passagens no arquivo, mas ainda evitaria armazenar o arquivo inteiro na memória.
Outra vantagem sobre o GNU
shuf
é que ele preserva a ordem das linhas no arquivo.Note-se que ele assume
n
é o número de linhas no arquivo. Se você deseja imprimirp
as primeirasn
linhas do arquivo (que possui potencialmente mais linhas), precisará pararawk
nan
quinta linha, como:fonte
Gosto de usar o awk para isso quando quero preservar uma linha de cabeçalho e quando a amostra pode ser uma porcentagem aproximada do arquivo. Funciona para arquivos muito grandes:
fonte
Ou assim:
Na página do manual do bash:
fonte
Se o tamanho do arquivo não for grande, você poderá usar a opção Classificar aleatoriamente. Isso leva um pouco mais do que shuf, mas randomiza todos os dados. Portanto, você pode facilmente fazer o seguinte para usar o head conforme solicitado:
Isso classificaria o arquivo aleatoriamente e forneceria as primeiras 1000 linhas.
fonte
Como mencionado na resposta aceita, o GNU
shuf
suporta amostragem aleatória simples (shuf -n
) muito bem. Seshuf
forem necessários métodos de amostragem além daqueles suportados por , considere tsv-sample do TSV Utilities do eBay . Ele suporta vários modos de amostragem adicionais, incluindo amostragem aleatória ponderada, amostragem de Bernoulli e amostragem distinta. O desempenho é semelhante ao GNUshuf
(ambos são bastante rápidos). Disclaimer: Eu sou o autor.fonte