파일의 하위 집합을 무작위로 샘플링하는 방법


38

파일의 서브 세트를 샘플링하기 위해 사용할 수있는 Linux 명령이 있습니까? 예를 들어, 파일에는 백만 줄이 포함되어 있으며 해당 파일에서 천 줄만 무작위로 샘플링하려고합니다.

무작위로 나는 모든 라인이 동일한 확률을 선택하고 선택된 라인 중 어느 것도 반복적이지 않음을 의미합니다.

head그리고 tail하지만 무작위로 파일의 하위 집합을 선택할 수 있습니다. 나는 항상 파이썬 스크립트를 작성하여 그렇게 할 수 있다는 것을 알고 있지만이 사용법에 대한 명령이 궁금합니다.


임의의 순서로 라인 또는 해당 파일의 연속 1000 줄의 임의 블록?
frostschutz

모든 라인은 같은 확률로 선택됩니다. 연속적인 라인 블록이 함께 선택 될 가능성은 적지 만 연속적 일 필요는 없습니다. 그것에 대해 명확히하기 위해 내 질문을 업데이트했습니다. 감사.
clwen

github.com/barrycarter/bcapps/tree/master/bc-fastrand.pl 은 파일의 임의의 위치를 ​​찾고 가장 가까운 줄 바꿈을 찾아서이 작업을 수행합니다.
barrycarter

답변:


65

shuf명령 (로 coreutils의 일부)이 작업을 수행 할 수 있습니다

shuf -n 1000 file

그리고 적어도 지금은 고대 버전이 아닌 버전 ( 2013 에서 커밋에 추가됨)에서 적절한 경우 저장소 샘플링을 사용하므로 메모리가 부족하지 않고 빠른 알고리즘을 사용합니다.


문서에 따르면, 입력으로 정렬 된 파일이 필요합니다 : gnu.org/software/coreutils/manual/…
mkc

@Ketan, 그런 식으로 보이지 않습니다
frostschutz

2
@ Ketan 그것은 매뉴얼의 잘못된 섹션에 있다고 생각합니다. 매뉴얼의 예제조차도 정렬되지 않았습니다. 또한 sort같은 섹션에 있으며 정렬 된 입력이 필요하지 않습니다.
derobert

2
shuf버전의 coreutils에 도입되었으며 6.0 (2006-08-15), 합리적으로 일반적인 일부 시스템 (특히 CentOS 6.5)에는 해당 버전이 없습니다.
offby1

2
@petrelharp shuf -n은 적어도 입력이 8K보다 클 때 저수지 샘플링을 수행합니다.이 크기는 벤치 마크가 더 좋다고 결정했습니다. 소스 코드를 참조하십시오 (예 : github.com/coreutils/coreutils/blob/master/src/shuf.c#L46 ). 답변이 늦어서 죄송합니다. 분명히 그것은 6 년 전의 새로운 것입니다.
derobert

16

파일 이 매우 큰 경우 (샘플을 가져야하는 일반적인 이유) 다음을 발견 할 수 있습니다.

  1. shuf 메모리를 소진
  2. $RANDOM파일이 32767 줄을 초과하면 사용 이 제대로 작동하지 않습니다

"정확하게"n 개의 샘플링 된 라인필요하지 않은 경우 다음 과 같은 비율을 샘플링 할 수 있습니다 .

cat input.txt | awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01) print $0}' > sample.txt

이것은 일정한 메모리를 사용 하고 파일의 1 %를 샘플링합니다 (파일의 줄 수를 알고 있다면 제한된 수의 줄에 가깝게 샘플링하기 위해이 요소를 조정할 수 있습니다). 그러나 어떤 크기 의 파일 에서도 작동 하지는 않습니다. 정확한 수의 행을 반환하고 통계 비율 만 표시합니다.

참고 : 코드는 https://stackoverflow.com/questions/692312/randomly-pick-lines-from-a-file-without-slurping-it-with-unix 에서 제공됩니다.


사용자가 비 공백 행의 1 %를 원한다면 이것은 좋은 대답입니다. 그러나 사용자가 정확한 수의 줄을 원하면 (예 : 1000000 줄 파일 중 1000 개) 실패합니다. 당신이 얻은 대답에 따르면 통계적 추정치 만 산출합니다. 그리고 빈 줄을 무시하고 있음을 알기에 충분히 답을 이해합니까? 실제로 이것은 좋은 생각이지만 문서화되지 않은 기능은 일반적으로 좋은 생각이 아닙니다.
G-Man, 'Reinstate Monica'라고

1
PS   단순 접근 방식을 사용 $RANDOM하면 32767 라인보다 큰 파일에는 올바르게 작동하지 않습니다. “사용 $RANDOM이 전체 파일에 도달하지 않습니다 ”라는 문장 은 약간 광범위합니다.
G-Man, 'Reinstate

@ G-Man 예를 들어 백만에서 10k 라인을 얻는 것에 대해 이야기하는 것 같습니다. 파일 및 하드웨어 제한으로 인해 답이 나에게 도움이되지 않았으며 합리적인 타협으로 제안했습니다. 그것은 백만에서 10k 라인을 얻을 수는 없지만 대부분의 실제 목적에 충분히 가깝습니다. 나는 당신의 조언에 따라 조금 더 명확히했습니다. 감사.
Txangel

이것이 최선의 대답이며, 요구 사항 인 경우 원본 파일의 시간 순서를 고려하여 행을 임의로 선택합니다. 추가에 awk더 자원은보다 친절shuf
중합 효소

정확한 숫자가 필요한 경우 항상 다음을 수행 할 수 있습니다. 필요 이상으로 % 더 큰 값으로 실행하십시오. 결과를 세십시오. 카운트 모드 차이와 일치하는 라인을 제거하십시오.
Bruno Bronosky

6

@Txangel의 확률 적 솔루션과 유사하지만 100 배 더 빠르게 접근합니다.

perl -ne 'print if (rand() < .01)' huge_file.csv > sample.csv

고성능, 정확한 샘플 크기가 필요하고 파일 끝에 샘플 간격이 있으면 기꺼이 다음과 같은 작업을 수행 할 수 있습니다 (1m 라인 파일에서 1000 라인 샘플링).

perl -ne 'print if (rand() < .0012)' huge_file.csv | head -1000 > sample.csv

.. 또는 대신에 두 번째 샘플 방법을 연결 head합니다.


5

shuf -n큰 파일 의 트릭에 메모리가 부족하고 여전히 고정 크기 샘플이 필요하고 외부 유틸리티를 설치할 수있는 경우 샘플 을 시도하십시오 .

$ sample -N 1000 < FILE_WITH_MILLIONS_OF_LINES 

주의 할 점은 샘플 ( 예제 에서 1000 줄)이 메모리에 맞아야한다는 것입니다.

면책 조항 : 저는 권장 소프트웨어의 저자입니다.


1
이 파일을 설치하고 /usr/local/bin이전 /usr/bin/에 자신의 길 을 가고있는 사람들을 위해 macOS에는에있는 sample완전히 다른 기능 을하는 내장 콜 스택 샘플러가 제공된다는 점에주의하십시오 /usr/bin/.
데니스 드 버나 디

2

당신이 요구하는 것을 할 수있는 단일 명령을 알지 못하지만 여기에 내가 할 수있는 루프가 있습니다.

for i in `seq 1000`; do sed -n `echo $RANDOM % 1000000 | bc`p alargefile.txt; done > sample.txt

sed1000 패스마다 무작위 라인을 선택합니다. 더 효율적인 솔루션이있을 수 있습니다.


이 방법으로 같은 줄을 여러 번 얻을 수 있습니까?
clwen

1
예, 같은 줄 번호를 두 번 이상 얻을 수 있습니다. 또한 $RANDOM범위는 0에서 32767 사이입니다. 따라서 잘 분산 된 줄 번호를 얻지 못합니다.
mkc

하지 작업을 수행 - 랜덤 한 번라고
의 Bohdan

2

다음 코드를 파일 (예 : randextract.sh)에 저장하고 다음과 같이 실행할 수 있습니다.

randextract.sh file.txt

---- 파일 시작 ----

#!/bin/sh -xv

#configuration MAX_LINES is the number of lines to extract
MAX_LINES=10

#number of lines in the file (is a limit)
NUM_LINES=`wc -l $1 | cut -d' ' -f1`

#generate a random number
#in bash the variable $RANDOM returns diferent values on each call
if [ "$RANDOM." != "$RANDOM." ]
then
    #bigger number (0 to 3276732767)
    RAND=$RANDOM$RANDOM
else
    RAND=`date +'%s'`
fi 

#The start line
START_LINE=`expr $RAND % '(' $NUM_LINES - $MAX_LINES ')'`

tail -n +$START_LINE $1 | head -n $MAX_LINES

---- 파일 종료 ----


3
RAND로 무엇을하려고하는지 확실 $RANDOM$RANDOM하지 않지만 "0 ~ 3276732767"의 전체 범위에서 임의의 숫자를 생성하지 않습니다 (예 : 1000100000을 생성하지만 1000099999는 생성하지 않음).
Gilles 'SO- 악의를 멈추십시오'

OP는“모든 라인은 동일한 확률로 선택 될 수 있습니다. … 연속 된 라인 블록이 함께 선택 될 가능성은 아주 적습니다.”또한이 답변은 암호로 보이지만 임의의 시작점에서 10 라인의 연속 라인 블록을 추출하는 것처럼 보입니다. 그것은 OP가 요구하는 것이 아닙니다.
G-남자 '는 분석 재개 모니카'말한다

2

파일의 줄 수를 알고 있으면 (예 : 1e6) 다음을 수행 할 수 있습니다.

awk -v n=1e6 -v p=1000 '
  BEGIN {srand()}
  rand() * n-- < p {p--; print}' < file

그렇지 않은 경우 언제든지 할 수 있습니다

awk -v n="$(wc -l < file)" -v p=1000 '
  BEGIN {srand()}
  rand() * n-- < p {p--; print}' < file

파일에서 두 번의 패스를 수행하지만 전체 파일을 메모리에 저장하지 마십시오.

GNU에 비해 ​​또 다른 장점 shuf은 파일의 줄 순서를 유지한다는 것입니다.

이 가정합니다 참고 n 파일의 행의 수. 파일 p첫 번째 n 행 (여러 줄이 더 있을 수 있음)을 인쇄 하려면 다음 과 같이 세 번째awk에서 중지해야합니다 .n

awk -v n=1e6 -v p=1000 '
  BEGIN {srand()}
  rand() * n-- < p {p--; print}
  !n {exit}' < file

2

헤더 행을 유지하고 샘플이 파일의 대략적인 백분율이 될 때 awk를 사용하는 것이 좋습니다. 매우 큰 파일에서 작동합니다.

awk 'BEGIN {srand()} !/^$/ { if (rand() <= .01 || FNR==1) print > "data-sample.txt"}' data.txt

1

또는 이렇게 :

LINES=$(wc -l < file)  
RANDLINE=$[ $RANDOM % $LINES ]  
tail -n $RANDLINE  < file|head -1  

bash 매뉴얼 페이지에서 :

        RANDOM이 매개 변수가 참조 될 때마다 임의의 정수
              0에서 32767 사이가 생성됩니다. 무작위의 순서
              RAN에 값을 할당하여 숫자를 초기화 할 수 있습니다.
              DOM. RANDOM이 설정되어 있지 않으면 특수 특성이 손실됩니다.
              이후에 재설정 되더라도 연결됩니다.

파일의 줄 수가 32767보다 작 으면 실패합니다.
offby1

파일에서 줄을 출력 합니다. (당신의 아이디어는 루프에서 위의 명령을 실행하는 것 같아요?) 파일에 32767 줄 이상 이 있으면 이러한 명령은 첫 번째 32767 줄에서만 선택됩니다. 가능한 비 효율성을 제외하고 파일에 32767 줄 미만인 경우이 답변에 큰 문제가 발생하지 않습니다.
G-남자 '는 분석 재개 모니카'말한다

1

파일 크기가 크지 않으면 임의 정렬을 사용할 수 있습니다. 이것은 shuf보다 조금 오래 걸리지 만 전체 데이터를 무작위로 만듭니다. 따라서 요청한대로 head를 사용하기 위해 다음을 쉽게 수행 할 수 있습니다.

sort -R input | head -1000 > output

이것은 파일을 무작위로 정렬하고 처음 1000 줄을 줄 것입니다.


0

허용되는 답변에서 언급했듯이 GNU shuf는 간단한 무작위 샘플링 ( shuf -n)을 아주 잘 지원합니다 . 지원되는 것 이외의 샘플링 방법 shuf이 필요한 경우 eBay의 TSV 유틸리티 에서 tsv-sample 을 고려하십시오 . 가중 랜덤 샘플링, 베르누이 (Beroulli) 샘플링 및 고유 한 샘플링을 포함하여 몇 가지 추가 샘플링 모드를 지원합니다. 성능은 GNU와 비슷합니다 (둘 다 빠릅니다). 면책 조항 : 나는 저자입니다.shuf

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.