Saya punya daftar data, seperti
12345
23456
67891
-20000
200
600
20
...
Asumsikan ukuran kumpulan data ini (yaitu baris file) adalah N
. Saya ingin menggambar m
garis secara acak dari file data ini. Oleh karena itu, output harus berupa dua file, satu file termasuk m
baris data ini, dan yang lainnya mencakup N-m
baris data.
Apakah ada cara untuk melakukan itu menggunakan perintah Linux?
linux
shell
text-processing
pengguna288609
sumber
sumber
Jawaban:
Ini mungkin bukan cara yang paling efisien tetapi berhasil:
Dengan
$m
mengandung jumlah garis.sumber
sort -R
keacakan. Tidak yakin jika Anda menurunkan jawaban untuk itu, tetapi cari dulu di halaman manual.sort -R
tidak persis mengurutkan inputnya secara acak: itu mengelompokkan garis yang identik. Jadi jika input misalnyafoo
,foo
,bar
,bar
dan m = 2, maka satu file akan mengandungfoo
dan yang lainnya akan mengandung keduabar
s. GNU coreutils juga memilikishuf
, yang mengacak jalur input. Selain itu, Anda tidak memerlukan file sementara .shuf <file> |head -n $m
?Skrip bash / awk ini memilih baris secara acak, dan mempertahankan urutan asli di kedua file output.
Keluaran, berdasarkan pada data dalam pertanyaan.
sumber
Seperti semua hal Unix, Ada Utilitas untuk TM Itu .
Program hari ini:
split
split
akan membagi file dengan berbagai cara,-b
byte,-l
baris,-n
jumlah file output. Kami akan menggunakan-l
opsi. Karena Anda ingin memilih garis acak dan bukan hanya yang pertamam
, kami akansort
file secara acak terlebih dahulu. Jika Anda ingin membacasort
, lihat jawaban saya di sini .Sekarang, kode yang sebenarnya. Ini cukup sederhana, sungguh:
Ini akan membuat dua file, satu dengan
m
garis dan satu denganN-m
garis, bernamaoutput_prefixaa
danoutput_prefixab
. Pastikanm
adalah file yang lebih besar yang Anda inginkan atau Anda akan mendapatkan beberapa file dengan panjangm
(dan satu denganN % m
).Jika Anda ingin memastikan bahwa Anda menggunakan ukuran yang benar, berikut ini sedikit kode untuk melakukannya:
Sunting: Telah menjadi perhatian saya bahwa beberapa
sort
implementasi tidak memiliki-R
bendera. Jika sudahperl
, Anda bisa menggantinyaperl -e 'use List::Util qw/shuffle/; print shuffle <>;'
.sumber
sort -R
tampaknya hanya ada di beberapa versi semacam (mungkin versi gnu). Untuk platform lain saya menulis alat yang disebut 'randline' yang tidak melakukan apa-apa selain mengacak stdin. Ini di beesbuzz.biz/code untuk siapa saja yang membutuhkannya. (Saya cenderung mengacak konten file cukup banyak.)sort -R
tidak persis mengurutkan inputnya secara acak: itu mengelompokkan garis yang identik. Jadi jika input misalnyafoo
,foo
,bar
,bar
dan m = 2, maka satu file akan mengandungfoo
dan yang lainnya akan mengandung keduabar
s. GNU coreutils juga memilikishuf
, yang mengacak jalur input. Juga, Anda dapat memilih nama file output dengan menggunakanhead
dantail
bukansplit
.Jika Anda tidak keberatan menata ulang baris dan Anda memiliki GNU coreutils (yaitu pada Linux yang tidak tertanam atau Cygwin, tidak terlalu kuno sejak
shuf
muncul di versi 6.0),shuf
("acak") mengatur ulang baris file secara acak. Jadi Anda dapat mengacak file dan mengirim baris m pertama ke dalam satu file dan sisanya ke yang lain.Tidak ada cara ideal untuk melakukan pengiriman itu. Anda tidak bisa hanya rantai
head
dantail
karenahead
akan buffer di depan. Anda dapat menggunakansplit
, tetapi Anda tidak mendapatkan fleksibilitas sehubungan dengan nama file output. Anda bisa menggunakanawk
, tentu saja:Anda dapat menggunakan
sed
, yang tidak jelas tetapi mungkin lebih cepat untuk file besar.Atau Anda dapat menggunakan
tee
untuk menggandakan data, jika platform Anda memiliki/dev/fd
; tidak apa-apa jika m kecil:Dengan mudah, Anda dapat menggunakan awk untuk mengirimkan setiap baris secara bergantian. Perhatikan bahwa awk tidak pandai menginisialisasi generator angka acaknya; keacakan tidak hanya pasti tidak cocok untuk kriptografi, tetapi bahkan tidak terlalu baik untuk simulasi numerik. Benih akan sama untuk semua doa awk pada sistem apa pun dengan periode satu detik.
Jika Anda membutuhkan keacakan yang lebih baik, Anda dapat melakukan hal yang sama di Perl, yang menanamkan RNG dengan baik.
sumber
awk
contoh:-v N=$(wc -l <file) -v m=4
... dan itu hanya mencetak garis "acak" ketika nilai acak kurang dari$m
, daripada mencetak$m
garis acak ... Tampaknyaperl
mungkin melakukan hal yang sama dengan rand , tapi saya tidak tahuperl
cukup baik untuk melewati kesalahan kompilasi: kesalahan sintaks pada -e baris 7, dekat ") print"shuf
contoh.head
cat
combo menyebabkan hilangnya data sebagai berikut tes kedua 3-4 .... UJI 1-2{ for i in {00001..10000} ;do echo $i; done; } | { head -n 5000 >out1; cat >out2; }
.. UJI 3-4{ for i in {00001..10000} ;do echo $i; done; } >input; cat input | { head -n 5000 >out3; cat >out4; }
...wc -l
hasil untuk output dari UJI 1-2 adalah 5000 5000 (baik), tapi untuk UJI 3-4 adalah 5000 4539 (tidak baik) .. Perbedaannya tergantung pada ukuran file yang terlibat ... Berikut ini tautan ke kode pengujianhead
baca di depan; apa yang dibaca di depan dan tidak dicetak dibuang. Saya telah memperbarui jawaban saya dengan kurang elegan tetapi (saya cukup yakin) solusi yang benar.Dengan asumsi
m = 7
danN = 21
:Catatan: Jika Anda mengganti
7
dengan variabel seperti$1
atau$m
, Anda harus menggunakanseq
, bukan{from..to}
-notasi, yang tidak melakukan ekspansi variabel.Ia bekerja dengan menghapus baris demi baris dari file, yang semakin pendek dan lebih pendek, sehingga nomor baris, yang dapat dihapus, harus semakin kecil.
Ini tidak boleh digunakan untuk file yang lebih panjang, dan banyak baris, karena untuk setiap angka, rata-rata, setengah file harus dibaca untuk tanggal 1, dan seluruh file untuk kode sed kedua .
sumber
including them
tetapi garis asli juga - karena ituincluding
, tidakconsisting of
, dan tidak menggunakanonly
, tapi saya kira interpretasi Anda adalah, apa yang dimaksud user288609. Saya akan menyesuaikan skrip saya sesuai.+1
salah meletakkannya di tempat. Itu harus dirnd=$((RANDOM%(N-i)+1))
mana N = 21 dalam contoh Anda .. Saat ini menyebabkansed
crash ketikarnd
dievaluasi0
. .. Juga, itu tidak berskala sangat baik dengan semua file yang ditulis ulang. mis. 123 detik untuk mengekstrak 5.000 baris acak dari 10.000 baris file vs. 0,03 detik untuk metode yang lebih langsung ...