Mam listę danych, na przykład
12345
23456
67891
-20000
200
600
20
...
Załóżmy, że rozmiar tego zestawu danych (tj. Wierszy pliku) wynosi N
. Chcę losowo narysować m
linie z tego pliku danych. Dlatego dane wyjściowe powinny zawierać dwa pliki, jeden to plik zawierający te m
wiersze danych, a drugi zawiera N-m
wiersze danych.
Czy można to zrobić za pomocą komendy Linux?
linux
shell
text-processing
użytkownik 288609
źródło
źródło
Odpowiedzi:
To może nie być najbardziej efektywny sposób, ale działa:
Z
$m
zawierające liczbę wierszy.źródło
sort -R
dba o losowość. Nie jestem pewien, czy głosowałeś za odpowiedzią na to pytanie, ale najpierw sprawdź ją na stronie podręcznika.sort -R
nie sortuje dokładnie danych wejściowych losowo: grupuje identyczne linie. Tak więc, jeśli sygnał wejściowy jest na przykładfoo
,foo
,bar
,bar
a m = 2, wówczas jeden plik zawiera zarównofoo
S, a drugi zawiera zarównobar
s. Coreutils GNU również mashuf
, który losowo linie wejściowe. Ponadto nie potrzebujesz pliku tymczasowego .shuf <file> |head -n $m
?Ten skrypt bash / awk wybiera linie losowo i zachowuje oryginalną sekwencję w obu plikach wyjściowych.
Dane wyjściowe na podstawie danych zawartych w pytaniu.
źródło
Podobnie jak w przypadku wszystkich innych systemów uniksowych, istnieje narzędzie dla tej TM .
Program dnia:
split
split
podzieli plik na wiele różnych sposobów,-b
bajtów,-l
linii,-n
liczby plików wyjściowych. Będziemy korzystać z tej-l
opcji. Ponieważ chcesz wybrać losowe linie, a nie tylko pierwszem
,sort
plik zostanie losowo wybrany jako pierwszy. Jeśli chcesz przeczytać osort
, zapoznaj się z moją odpowiedzią tutaj .Teraz aktualny kod. To całkiem proste, naprawdę:
To utworzy dwa pliki, jeden z
m
liniami i jeden zN-m
liniami, o nazwachoutput_prefixaa
ioutput_prefixab
. Upewnij się,m
że potrzebujesz większego pliku, w przeciwnym razie otrzymasz kilka plików o długościm
(i jeden zN % m
).Jeśli chcesz upewnić się, że używasz właściwego rozmiaru, oto mały kod, aby to zrobić:
Edycja: Zwróciłem uwagę, że niektóre
sort
implementacje nie mają-R
flagi. Jeśli takperl
, możesz zastąpićperl -e 'use List::Util qw/shuffle/; print shuffle <>;'
.źródło
sort -R
wydaje się , że jest tylko w niektórych wersjach (prawdopodobnie w wersji GNU). Dla innych platform napisałem narzędzie o nazwie „randline”, które nie robi nic poza losowaniem standardowego wejścia. Jest na beesbuzz.biz/code dla każdego, kto tego potrzebuje. (Często tasuję zawartość pliku.)sort -R
nie sortuje dokładnie danych wejściowych losowo: grupuje identyczne linie. Tak więc, jeśli sygnał wejściowy jest na przykładfoo
,foo
,bar
,bar
a m = 2, wówczas jeden plik zawiera zarównofoo
S, a drugi zawiera zarównobar
s. Coreutils GNU również mashuf
, który losowo linie wejściowe. Ponadto można wybrać nazwy pliku wyjściowego poprzez wykorzystaniehead
itail
zamiastsplit
.Jeśli nie masz nic przeciwko zmianie kolejności wierszy i masz jądra GNU (tj. W niewbudowanym systemie Linux lub Cygwin, niezbyt stare od czasu
shuf
pojawienia się w wersji 6.0),shuf
funkcja „losowo” zmienia kolejność wierszy pliku losowo. Możesz więc przetasować plik i wysłać pierwsze m wierszy do jednego pliku, a resztę do innego.Nie ma idealnego sposobu na wykonanie tej wysyłki. Nie możesz po prostu połączyć w łańcuch,
head
atail
ponieważhead
buforowałby do przodu. Możesz użyćsplit
, ale nie zyskujesz elastyczności w odniesieniu do nazw plików wyjściowych. Możeszawk
oczywiście użyć :Możesz użyć
sed
, co jest niejasne, ale być może szybsze w przypadku dużych plików.Lub możesz użyć
tee
do skopiowania danych, jeśli Twoja platforma ma/dev/fd
; to dobrze, jeśli m jest małe:Przenośnie, możesz użyć awk, aby wywołać każdą linię po kolei. Zauważ, że awk nie jest zbyt dobry w inicjowaniu generatora liczb losowych; losowość nie tylko zdecydowanie nie nadaje się do kryptografii, ale nawet nie jest bardzo dobra do symulacji numerycznych. Ziarno będzie takie samo dla wszystkich wywołań awk w dowolnym systemie z okresem jednej sekundy.
Jeśli potrzebujesz lepszej losowości, możesz zrobić to samo w Perlu, który porządnie zasiewa RNG.
źródło
awk
przykład:-v N=$(wc -l <file) -v m=4
... i wypisuje „losową” linię, gdy losowa wartość jest mniejsza niż$m
, zamiast wypisywać$m
losowe linie… Wygląda na to, żeperl
to samo robi z Rand , ale nie nie wiemperl
wystarczająco dobrze, aby ominąć błąd kompilacji: błąd składni w -e wierszu 7, w pobliżu „) print”shuf
przykładzie.head
cat
Combo powoduje utraty danych w następujących drugim teście 3-4 .... TEST 1-2{ for i in {00001..10000} ;do echo $i; done; } | { head -n 5000 >out1; cat >out2; }
.. TEST 3-4{ for i in {00001..10000} ;do echo $i; done; } >input; cat input | { head -n 5000 >out3; cat >out4; }
...wc -l
Wyniki dla wyjść TEST 1-2 są 5000 5000 (dobre), ale dla TEST 3-4 to 5000 4539 (źle). Różnice różnią się w zależności od rozmiaru plików ... Oto link do mojego kodu testowegohead
czyta z przodu; to, co czyta z wyprzedzeniem i nie drukuje, jest odrzucane. Zaktualizowałem odpowiedź o mniej eleganckie, ale (jestem dość pewny) prawidłowe rozwiązania.Zakładając
m = 7
iN = 21
:Uwaga: Jeśli zastąpisz
7
zmienną taką jak$1
lub$m
, musisz użyćseq
, a nie{from..to}
adnotacji, która nie powoduje rozszerzenia zmiennych.Działa poprzez usuwanie linia po linii z pliku, który staje się coraz krótszy, więc numer linii, który można usunąć, musi być coraz mniejszy.
Nie należy tego używać w przypadku dłuższych plików i wielu wierszy, ponieważ dla każdej liczby średnio połowa pliku musi zostać odczytana dla pierwszego, a cały plik dla drugiego kodu sed .
źródło
including them
ale również oryginalne wiersze - dlategoincluding
nieconsisting of
i nie używamonly
, ale myślę, że twoja interpretacja jest tym, co użytkownik 288609 miał na myśli. Dostosuję odpowiednio mój skrypt.+1
niewłaściwe miejsce. Powinno to być miejsce, wrnd=$((RANDOM%(N-i)+1))
którym N = 21 w twoim przykładzie. Obecnie powodujesed
awarię, gdyrnd
jest oceniany na0
. .. Poza tym nie skaluje się zbyt dobrze przy całym tym ponownym zapisywaniu plików. np. 123 sekundy, aby wyodrębnić 5000 losowych linii z pliku 10.000 linii w porównaniu do 0,03 sekundy dla bardziej bezpośredniej metody ...