Apakah ada perintah Linux yang dapat digunakan untuk sampel subset file? Misalnya, file berisi satu juta baris, dan kami ingin mengambil sampel acak hanya seribu baris dari file itu.
Secara acak saya maksudkan bahwa setiap baris mendapatkan probabilitas yang sama untuk dipilih dan tidak ada baris yang dipilih yang berulang.
head
dan tail
dapat memilih subset file tetapi tidak secara acak. Saya tahu saya selalu bisa menulis skrip python untuk melakukannya tetapi hanya ingin tahu apakah ada perintah untuk penggunaan ini.
command-line
files
command
Clwen
sumber
sumber
Jawaban:
The
shuf
perintah (bagian dari coreutils) dapat melakukan ini:Dan setidaknya untuk versi non-kuno sekarang (ditambahkan dalam komit dari 2013 ), yang akan menggunakan pengambilan sampel reservoir jika sesuai, artinya tidak boleh kehabisan memori dan menggunakan algoritma cepat.
sumber
sort
ada di bagian yang sama, dan itu jelas tidak memerlukan input yang diurutkan.shuf
diperkenalkan ke coreutils dalam versi6.0 (2006-08-15)
, dan percaya atau tidak, beberapa sistem yang cukup umum (CentOS 6.5 khususnya) tidak memiliki versi itu: - |shuf -n
melakukan sampling reservoir, setidaknya ketika input lebih besar dari 8K, yang merupakan ukuran yang mereka tentukan adalah tolok ukur yang lebih baik. Lihat kode sumber (misalnya, di github.com/coreutils/coreutils/blob/master/src/shuf.c#L46 ). Maaf atas jawaban yang sangat terlambat ini. Rupanya itu baru 6 tahun yang lalu.Jika Anda memiliki file yang sangat besar (yang merupakan alasan umum untuk mengambil sampel), Anda akan menemukan bahwa:
shuf
kehabisan memori$RANDOM
tidak akan berfungsi dengan benar jika file melebihi 32767 barisJika Anda tidak membutuhkan "tepat" di baris sampel, Anda dapat mencicipi rasio seperti ini:
cat input.txt | awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01) print $0}' > sample.txt
Ini menggunakan memori konstan , sampel 1% dari file (jika Anda tahu jumlah baris file Anda dapat menyesuaikan faktor ini untuk sampel yang mendekati jumlah baris terbatas), dan bekerja dengan ukuran file berapa pun tetapi tidak akan mengembalikan tepat jumlah baris, hanya rasio statistik.
Catatan: Kode tersebut berasal dari: https://stackoverflow.com/questions/692312/randomly-pick-lines-from-a-file-without-slurping-it-with-unix
sumber
$RANDOM
tidak akan berfungsi dengan benar untuk file yang lebih besar dari 32767 baris. Pernyataan "Menggunakan$RANDOM
tidak mencapai seluruh file" agak luas.awk
lebih ramah sumber daya daripadashuf
Mirip dengan solusi probabilistik @ Txangel tetapi mendekati 100x lebih cepat.
Jika Anda membutuhkan kinerja tinggi, ukuran sampel yang tepat, dan senang tinggal dengan celah sampel di akhir file, Anda dapat melakukan sesuatu seperti berikut (sampel 1000 baris dari file baris 1m):
.. Atau memang rantai metode sampel kedua alih-alih
head
.sumber
Jika
shuf -n
trik pada file besar kehabisan memori dan Anda masih perlu sampel ukuran tetap dan utilitas eksternal dapat diinstal kemudian coba sampel :Peringatannya adalah bahwa sampel (1000 baris dalam contoh) harus sesuai dengan memori.
Penafian: Saya adalah pembuat perangkat lunak yang direkomendasikan.
sumber
/usr/local/bin
sebelum mereka/usr/bin/
di jalan mereka, berhati-hatilah bahwa macOS datang dengan built-in call-stack sampler yang disebutsample
, yang melakukan sesuatu yang sama sekali berbeda, di/usr/bin/
.Tidak mengetahui adanya perintah tunggal yang bisa melakukan apa yang Anda minta tetapi di sini ada satu loop yang saya kumpulkan yang dapat melakukan pekerjaan:
sed
akan mengambil garis acak pada masing-masing 1000 pass. Mungkin ada solusi yang lebih efisien.sumber
$RANDOM
memiliki rentang antara 0 dan 32767. Jadi, Anda tidak akan mendapatkan nomor baris yang tersebar dengan baik.Anda dapat menyimpan kode ikuti dalam file (dengan contoh randextract.sh) dan jalankan sebagai:
---- FILE AWAL ----
---- FILE AKHIR ----
sumber
$RANDOM$RANDOM
tidak menghasilkan angka acak di seluruh rentang "0 hingga 3276732767" (misalnya, itu akan menghasilkan 1000100000 tetapi tidak 1000099999).Jika Anda tahu jumlah baris dalam file (seperti 1e6 dalam kasus Anda), Anda dapat melakukan:
Jika tidak, Anda selalu bisa melakukannya
Itu akan melakukan dua lintasan dalam file, tetapi masih menghindari menyimpan seluruh file dalam memori.
Keuntungan lain dari GNU
shuf
adalah menjaga urutan baris dalam file.Perhatikan bahwa diasumsikan
n
adalah jumlah baris dalam file. Jika Anda ingin mencetakp
keluar dari pertaman
baris dari file (yang memiliki potensial lebih baris), Anda akan perlu untuk berhentiawk
din
th baris seperti:sumber
Saya suka menggunakan awk untuk ini ketika saya ingin mempertahankan baris tajuk, dan ketika sampel bisa menjadi persentase perkiraan file. Bekerja untuk file yang sangat besar:
sumber
Atau seperti ini:
Dari halaman bash man:
sumber
Jika ukuran file Anda tidak besar, Anda dapat menggunakan Sort secara acak. Ini membutuhkan waktu sedikit lebih lama daripada shuf, tetapi ini mengacak seluruh data. Jadi, Anda dapat dengan mudah melakukan hal berikut untuk menggunakan kepala seperti yang Anda minta:
Ini akan mengurutkan file secara acak dan memberi Anda 1000 baris pertama.
sumber
Seperti disebutkan dalam jawaban yang diterima, GNU
shuf
mendukung simple random sampling (shuf -n
) dengan cukup baik. Jika diperlukan metode pengambilan sampel di luar yang didukungshuf
, pertimbangkan sampel-tsv dari TSV Utilities eBay . Ini mendukung beberapa mode pengambilan sampel tambahan, termasuk pengambilan sampel acak tertimbang, pengambilan sampel Bernoulli, dan pengambilan sampel yang berbeda. Performanya mirip dengan GNUshuf
(keduanya cukup cepat). Penafian: Saya penulis.sumber