파일 모음에서 임의의 샘플을 수집하는 가장 좋은 방법


23

300 개의 데이터 파일을 보유한 디렉토리가 있다고 가정하십시오. 해당 파일 중 200 개를 임의로 선택하여 다른 디렉토리로 옮기고 싶습니다. 유닉스 / 리눅스에서 그렇게 할 수있는 방법이 있습니까?


R 은 아마도 이것을 가진 눈의 반짝임에서 이것을 할 수있다 list.files().
sr_

4
나는 모호하게 연결 shuf하고 head(또는 그냥 사용 shuf -n, 맨 페이지를 읽어야합니다 ...)
Ulrich Schwarz

답변:


32

시스템에가 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

7
아, 그렇습니다. 왜냐하면 정렬 도구보다 셔플 링을 찾을 수 있기 때문입니다. (적어도 정렬과 반대이므로 shuf호출되지 않습니다 tros.)
Ulrich Schwarz

2
정렬과 반대되는 것은 없습니다 ( "날씨 없음"과 같은 의미는 없습니다). 무작위는 여전히 정렬되어 있으며 무작위로 정렬됩니다.
Plutor

1
"-zen200"은 무엇입니까? 그것은 shuf에 대한 문서 또는 인터넷의 어느 곳에도 없지만 예제가 없으면 작동하지 않습니다. 꽤 신비로운.
SigmaX 2019

2
@SigmaX 사실, 선 (quite)은 그렇지 않습니다. 힌트 : 3 개의 개별 플래그입니다.
케빈

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

2

모든 파일 이름을 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

동일한 파일을 두 번 이상 선택할 수 있습니다.
glenn jackman

아주 좋은 쉘 스크립트. 200 개 파일을 못하고의 문제를 해결하기 위해, 당신은 아마 저수지 샘플링을 사용하려면 : en.wikipedia.org/wiki/Reservoir_sampling 내가 약한 것이 아니라이의 쉘 스크립트 예제를 포함하고있다.
Bruce Ediger

@ glennjackman : 예, 썼습니다. 배열에서 항목을 제거하는 방법을 알아내는 데 몇 분이 걸렸습니다.
사용자가 알 수 없음

경미한 경고 : $RANDOM0에서 32767 사이의 값만 가질 수 있으므로 32768 개가 넘는 파일이 있으면 제대로 작동하지 않습니다. 또한 페치는 첫 번째 파일을 향해 바이어스됩니다.
l0b0

@ l0b0 : 300에서 200을 선택해야하는 요구 사항. 파일이 현재 디렉토리에 있지 않지만 파일 서버에있는 경우에도 작동하지 않습니다. 다른 요구 사항, 다른 답변.
사용자가 알 수 없음

2

통계적으로 임의적이어야하는 경우을 사용하지 않아야합니다 RANDOM % ${#keys[@]}. 치다:

  1. $RANDOM 32768 개의 고유 한 값이 있습니다
  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)

2

Kevin의 솔루션이 훌륭하게 작동합니다! 머리 꼭대기에서 기억하기가 더 쉽기 때문에 많이 사용했습니다.

cp `ls | shuf -n 200` destination

0

bash의 한 라이너 :

ls original_directory/|sort -R|head -number_of_files_to_move|while read file; do cp "new_directory/"$file test; done

정교하게 작성하십시오. U & L은 지식 기반입니다.
카운터 모드
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.