Czy jest jakieś polecenie Linuksa, którego można użyć do próbkowania podzbioru pliku? Na przykład plik zawiera milion wierszy, a my chcemy losowo pobrać próbkę tylko tysiąca wierszy z tego pliku.
Dla losowych mam na myśli to, że każda linia ma takie samo prawdopodobieństwo wyboru i żadna z wybranych linii nie jest powtarzalna.
head
i tail
może wybrać podzbiór pliku, ale nie losowo. Wiem, że zawsze mogę napisać skrypt Pythona, ale zastanawiam się, czy istnieje takie polecenie.
command-line
files
command
clwen
źródło
źródło
Odpowiedzi:
shuf
Komenda (część coreutils) może to zrobić:I przynajmniej na razie nie starożytne wersje (dodane w zatwierdzeniu z 2013 r. ), Które w razie potrzeby będą wykorzystywać próbkowanie zbiornika, co oznacza, że nie powinno zabraknąć pamięci i korzysta z szybkiego algorytmu.
źródło
sort
znajduje się w tej samej sekcji i wyraźnie nie wymaga posortowanych danych wejściowych.shuf
został wprowadzony do coreutils w wersji6.0 (2006-08-15)
i wierzcie lub nie, niektóre dość powszechne systemy (w szczególności CentOS 6.5) nie mają tej wersji: - |shuf -n
wykonuje próbkowanie w zbiorniku, przynajmniej wtedy, gdy sygnał wejściowy jest większy niż 8 KB, co oznacza, że rozmiar, który ustalili, jest lepszy w testach porównawczych. Zobacz kod źródłowy (np. Na github.com/coreutils/coreutils/blob/master/src/shuf.c#L46 ). Przepraszam za tę bardzo późną odpowiedź. Najwyraźniej to nowość sprzed 6 lat.Jeśli masz bardzo duży plik (co jest częstym powodem do pobrania próbki), przekonasz się, że:
shuf
wyczerpuje pamięć$RANDOM
nie będzie działać poprawnie, jeśli plik przekroczy 32767 liniiJeśli nie potrzebujesz „dokładnie” n próbkowanych linii , możesz próbkować taki współczynnik :
cat input.txt | awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01) print $0}' > sample.txt
Ten wykorzystuje stałą pamięć , próbki 1% pliku (jeśli wiesz liczbę wierszy w pliku można dostosować ten czynnik do próbki blisko do ograniczonej liczby linii) i współpracuje z dowolnym rozmiarze pliku, ale to nie będzie zwraca dokładną liczbę wierszy, tylko współczynnik statystyczny.
Uwaga: kod pochodzi z: https://stackoverflow.com/questions/692312/randomly-pick-lines-from-a-file-without-slurping-it-with-unix
źródło
$RANDOM
nie działa poprawnie dla plików większych niż 32767 linii. Stwierdzenie „Korzystanie$RANDOM
nie obejmuje całego pliku” jest nieco ogólne.awk
jest bardziej przyjazny dla zasobów niżshuf
Podobne do probabilistycznego rozwiązania @ Txangel, ale zbliża się 100 razy szybciej.
Jeśli potrzebujesz wysokiej wydajności, dokładnej wielkości próbki i z przyjemnością żyjesz z przerwą na próbkę na końcu pliku, możesz zrobić coś takiego: (próbkuje 1000 linii z pliku linii 1m):
.. lub w rzeczywistości łańcuch drugiej metody próbnej zamiast
head
.źródło
Jeśli w przypadku
shuf -n
dużych plików zabraknie pamięci i nadal potrzebujesz próbki o stałym rozmiarze i można zainstalować narzędzie zewnętrzne, wypróbuj próbkę :Zastrzeżenie polega na tym, że próbka (1000 linii w przykładzie) musi zmieścić się w pamięci.
Oświadczenie: Jestem autorem zalecanego oprogramowania.
źródło
/usr/local/bin
wcześniej/usr/bin/
na swojej drodze, uważaj, aby macOS był wyposażony we wbudowany sampler stosów wywołańsample
, który robi coś zupełnie innego/usr/bin/
.Nie znam żadnego pojedynczego polecenia, które mogłoby zrobić to, o co prosisz, ale oto pętla, którą razem stworzyłem:
sed
odbierze losową linię na każdym z 1000 przejść. Być może istnieją bardziej wydajne rozwiązania.źródło
$RANDOM
ma zakres od 0 do 32767. Tak więc nie otrzymasz dobrze rozłożonych numerów linii.Możesz zapisać następujący kod w pliku (na przykład randextract.sh) i wykonać jako:
---- ROZPOCZNIJ PLIK ----
---- PLIK KOŃCOWY ----
źródło
$RANDOM$RANDOM
nie generuje liczb losowych w całym zakresie od „0 do 3276732767” (na przykład wygeneruje 1000100000, ale nie 1000099999).Jeśli znasz liczbę wierszy w pliku (np. 1e6 w twoim przypadku), możesz:
Jeśli nie, zawsze możesz to zrobić
Spowodowałoby to dwa przejścia do pliku, ale nadal pozwalałoby uniknąć przechowywania całego pliku w pamięci.
Kolejną zaletą w stosunku do GNU
shuf
jest to, że zachowuje kolejność linii w pliku.Zauważ, że zakłada
n
ona liczbę wierszy w pliku. Jeśli chcesz drukowaćp
z tych pierwszychn
linii pliku (który ma potencjalnie więcej linii), trzeba by zatrzymaćawk
wn
XX linii, takich jak:źródło
Lubię używać awk do tego, gdy chcę zachować wiersz nagłówka i kiedy próbka może stanowić przybliżony procent pliku. Działa dla bardzo dużych plików:
źródło
Lub tak:
Ze strony podręcznika użytkownika bash:
źródło
Jeśli rozmiar pliku nie jest ogromny, możesz użyć opcji Sortuj losowo. Trwa to trochę dłużej niż shuf, ale losuje całe dane. Możesz więc z łatwością wykonać następujące czynności, aby użyć głowicy zgodnie z żądaniem:
Spowoduje to sortowanie pliku losowo i otrzymanie pierwszych 1000 wierszy.
źródło
Jak wspomniano w przyjętej odpowiedzi, GNU całkiem dobrze
shuf
obsługuje proste losowe próbkowanie (shuf -n
). Jeślishuf
potrzebne są metody próbkowania wykraczające poza obsługiwane przez , należy rozważyć tsv-sample z TSV Utilities na eBayu . Obsługuje kilka dodatkowych trybów próbkowania, w tym ważone losowe próbkowanie, próbkowanie Bernoulliego i próbkowanie odrębne. Wydajność jest podobna do GNUshuf
(oba są dość szybkie). Oświadczenie: Jestem autorem.źródło