파일 모음에서 무작위 샘플을 수집하는 가장 좋은 방법

파일 모음에서 무작위 샘플을 수집하는 가장 좋은 방법

300개의 데이터 파일이 포함된 디렉터리가 있다고 가정합니다. 이 파일 중 200개를 무작위로 선택하여 다른 디렉토리로 이동하고 싶습니다. Unix/Linux에서 이를 수행할 수 있는 방법이 있습니까?

답변1

시스템에 이 기능이 있으면 shuf매우 편리하게 사용할 수 있습니다(보기 흉한 파일 이름도 처리할 수 있음).

shuf -zen200 source/* | xargs -0 mv -t dest

그렇지 않지만 걸리는 것이 shuf있으면 다음과 같이 작동합니다.sort-R

find source -type f -print0 | sort -Rz | cut -d $'\0' -f-200 | xargs -0 mv -t dest

답변2

통계적 무작위성이 필요한 경우에는 사용하면 안 됩니다 RANDOM % ${#keys[@]}.

  1. $RANDOM32768개의 고유 값이 있습니다.
  2. 첫 번째 선택은 300개 요소 중 1개입니다.
  3. 32768 = 109 * 300 + 68

따라서 첫 번째 항목이 선택되면 처음 68개 요소 각각은 선택될 확률이 110/32768~=0.33569%이고, 나머지 232개 요소는 각각 109/32768~=0.33264%의 기회가 선택됩니다. . 선택은 다양한 기회로 여러 번 반복되지만 매번 첫 번째 요소가 편향되어 32768 % ${#keys[@]} -ne 0오류가 복합됩니다.

이건 공정해야 해이며 모든 파일 이름에서 작동합니다.

while IFS= read -r -d '' -u 9
do
    mv -- "$REPLY" /target/dir
done 9< <(find /source/dir -mindepth 1 -print0 | shuf -n 200 -z)

답변3

files=(*)
for (( i=0; i<200; i++ )); do
    keys=("${!files[@]}")
    rnd=$(( RANDOM % ${#keys[@]} ))
    key=${keys[$rnd]}
    mv "${files[$key]}" "$otherdir"
    unset files[$key]
done

답변4

bash에서 모든 파일 이름을 "files"라는 배열에 넣으십시오.

files=( * )

배열 크기:

echo ${#files[@]}

그 중 2/3를 표본 크기로 정의합니다.

take=$((2*${#files[@]}/3)) 

for i in $(seq 1 $take)
do
    r=$((RANDOM%${#files[@]})) 
    echo ${files[r]}
done

그러면 중복 항목이 선택되고공백 등이 포함된 파일 이름으로는 테스트 되지 않았습니다 .

중복을 피하는 가장 쉬운 방법은 모든 파일을 반복하고 2/3의 확률로 각 파일을 선택하는 것입니다. 그러나 이로 인해 반드시 200개의 파일이 생성되는 것은 아닙니다.

목록에서 파일을 선택하고 요구 사항을 충족하면 파일이 삭제됩니다.

#!/bin/bash
files=( * )
# define 2/3 of them as sample size:
take=$((2*${#files[@]}/3)) 

while (( i < $take ))
do
    r=$((RANDOM%${#files[@]})) 
    f=${files[r]}
    if [[ -n $f ]]
    then 
        i=$((i+1))    
        echo ${files[r]}
        unset files[r]    
    fi
done

관련 정보