¿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.
heady tailpuede 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
shufcomando (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
sortestá en la misma sección, y claramente no requiere una entrada ordenada.shufse 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 -nrealiza 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:
shufagota la memoria$RANDOMno 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.txtEsto 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
$RANDOMno funcionará correctamente para archivos de más de 32767 líneas. La afirmación "El uso$RANDOMno llega a todo el archivo" es un poco amplia.awkes más amigable con los recursos queshufSimilar 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 -ntruco 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/binantes/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:
sedrecogerá una línea aleatoria en cada uno de los 1000 pases. Posiblemente hay soluciones más eficientes.fuente
$RANDOMtiene 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$RANDOMno 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
shufes que conserva el orden de las líneas en el archivo.Tenga en cuenta que se supone que
nes el número de líneas en el archivo. Si desea imprimirpdesde las primerasnlíneas del archivo (que tiene potencialmente más líneas), deberá detenerseawken la líneanth 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:
ALEATORIO Cada vez que se hace referencia a este parámetro, un entero aleatorio Se genera entre 0 y 32767. La secuencia de al azar los números se pueden inicializar asignando un valor a RAN‐ DOM. Si RANDOM no está activado, pierde su propiedad especial. lazos, incluso si posteriormente se restablece.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
shufadmiteshuf -nbastante bien el muestreo aleatorio simple ( ). Sishufse 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