¿Hay algún comando de Linux que se pueda usar para muestrear un subconjunto de un archivo? Por ejemplo, un archivo contiene un millón de líneas, y queremos muestrear aleatoriamente solo mil líneas de ese archivo.
Por aleatorio quiero decir que cada línea tiene la misma probabilidad de ser elegida y ninguna de las líneas elegidas es repetitiva.
head
y tail
puede elegir un subconjunto del archivo pero no al azar. Sé que siempre puedo escribir un script de Python para hacerlo, pero me pregunto si hay un comando para este uso.
command-line
files
command
clwen
fuente
fuente
Respuestas:
El
shuf
comando (parte de coreutils) puede hacer esto:Y al menos por ahora versiones no antiguas (agregadas en un commit de 2013 ), que usarán muestreo de reservorios cuando sea apropiado, lo que significa que no debería quedarse sin memoria y está usando un algoritmo rápido.
fuente
sort
está en la misma sección, y claramente no requiere una entrada ordenada.shuf
se introdujo en coreutils en la versión6.0 (2006-08-15)
, y lo creas o no, algunos sistemas razonablemente comunes (CentOS 6.5 en particular) no tienen esa versión: - |shuf -n
realiza un muestreo de yacimientos, al menos cuando la entrada es mayor a 8K, que es el tamaño que determinaron que es mejor para los puntos de referencia. Vea el código fuente (por ejemplo, en github.com/coreutils/coreutils/blob/master/src/shuf.c#L46 ). Perdón por esta respuesta tan tardía. Aparentemente eso es nuevo a partir de hace 6 años.Si tiene un archivo muy grande (que es una razón común para tomar una muestra), encontrará que:
shuf
agota la memoria$RANDOM
no funcionará correctamente si el archivo supera las 32767 líneasSi no necesita "exactamente" n líneas muestreadas , puede muestrear una relación como esta:
cat input.txt | awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01) print $0}' > sample.txt
Esto usa memoria constante , muestrea el 1% del archivo (si conoce el número de líneas del archivo, puede ajustar este factor para muestrear un número cercano a un número limitado de líneas) y funciona con cualquier tamaño de archivo, pero no lo hará. devuelve un número preciso de líneas, solo una relación estadística.
Nota: El código proviene de: https://stackoverflow.com/questions/692312/randomly-pick-lines-from-a-file-without-slurping-it-with-unix
fuente
$RANDOM
no funcionará correctamente para archivos de más de 32767 líneas. La afirmación "El uso$RANDOM
no llega a todo el archivo" es un poco amplia.awk
es más amigable con los recursos queshuf
Similar a la solución probabilística de @Txangel, pero se acerca 100 veces más rápido.
Si necesita un alto rendimiento, un tamaño de muestra exacto y está contento de vivir con un espacio de muestra al final del archivo, puede hacer algo como lo siguiente (muestra 1000 líneas de un archivo de 1 m de línea):
.. o de hecho encadenar un segundo método de muestra en lugar de
head
.fuente
En caso de que el
shuf -n
truco en archivos grandes se quede sin memoria y aún necesite una muestra de tamaño fijo y se pueda instalar una utilidad externa, pruebe la muestra :La advertencia es que la muestra (1000 líneas en el ejemplo) debe caber en la memoria.
Descargo de responsabilidad: soy el autor del software recomendado.
fuente
/usr/local/bin
antes/usr/bin/
en su camino, tenga cuidado de que macOS viene con un muestreador de pila de llamadas incorporado llamadosample
, que hace algo completamente diferente, en/usr/bin/
.No conozco ningún comando único que pueda hacer lo que pides, pero aquí hay un bucle que armé que puede hacer el trabajo:
sed
recogerá una línea aleatoria en cada uno de los 1000 pases. Posiblemente hay soluciones más eficientes.fuente
$RANDOM
tiene un rango entre 0 y 32767. Por lo tanto, no obtendrá un número de línea bien extendido.Puede guardar el código de seguimiento en un archivo (por ejemplo randextract.sh) y ejecutarlo como:
---- INICIAR ARCHIVO ----
---- FIN DE ARCHIVO ----
fuente
$RANDOM$RANDOM
no genera números aleatorios en todo el rango "0 a 3276732767" (por ejemplo, generará 1000100000 pero no 1000099999).Si conoce el número de líneas en el archivo (como 1e6 en su caso), puede hacer lo siguiente:
Si no, siempre puedes hacer
Eso haría dos pases en el archivo, pero aún así evitaría almacenar todo el archivo en la memoria.
Otra ventaja sobre GNU
shuf
es que conserva el orden de las líneas en el archivo.Tenga en cuenta que se supone que
n
es el número de líneas en el archivo. Si desea imprimirp
desde las primerasn
líneas del archivo (que tiene potencialmente más líneas), deberá detenerseawk
en la línean
th como:fuente
Me gusta usar awk para esto cuando quiero preservar una fila de encabezado y cuando la muestra puede ser un porcentaje aproximado del archivo. Funciona para archivos muy grandes:
fuente
O así:
Desde la página de manual de bash:
fuente
Si el tamaño del archivo no es enorme, puede usar Ordenar al azar. Esto lleva un poco más de tiempo que shuf, pero aleatoriza todos los datos. Por lo tanto, puede hacer lo siguiente fácilmente para usar head como lo solicitó:
Esto ordenaría el archivo al azar y le daría las primeras 1000 líneas.
fuente
Como se menciona en la respuesta aceptada, GNU
shuf
admiteshuf -n
bastante bien el muestreo aleatorio simple ( ). Sishuf
se necesitan métodos de muestreo más allá de los admitidos por , considere tsv-sample de TSV Utilities de eBay . Admite varios modos de muestreo adicionales, incluidos el muestreo aleatorio ponderado, el muestreo de Bernoulli y el muestreo distinto. El rendimiento es similar a GNUshuf
(ambos son bastante rápidos). Descargo de responsabilidad: soy el autor.fuente