통계적 샘플링과 같은 종류의 임의 위치에서 n 개의 요소가 필요하다고 확신하는 경우 세트를 한 번 반복하여 샘플을 가져 와서 원하는대로 확률은입니다. 이 방법은 세트를 한 번만 반복 할 때보다 효율적입니다.이 프로그램의
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
public class SamplingFromSet {
public static void main(String[] args) {
Set<String> population = new TreeSet<>();
/*
* Populate the set
*/
final int popSize = 17;
for (int i=0; i<popSize; i++) {
population.add(getRandomString());
}
List<String> sample
= sampleFromPopulation(population, 3 /*sampleSize */);
System.out.println("population is");
System.out.println(population.toString());
System.out.println("sample is");
System.out.println(sample.toString());
}
/**
* Pick some samples for a population
* @param population
* @param sampleSize - number of samples
* @return
*/
private static <T>
List<T> sampleFromPopulation(Set<T> population
, int sampleSize) {
float sampleProb = ((float) sampleSize)/population.size();
List<T> sample = new ArrayList<>();
Iterator<T> iter = population.iterator();
while (iter.hasNext()) {
T element = iter.next();
if (random.nextFloat()<sampleProb) {
/*
* Lucky Draw!
*/
sample.add(element);
}
}
return sample;
}
private static Random random = new Random();
private static String getRandomString() {
return String.valueOf(random.nextInt());
}
}
출력 :
다음 프로그램이 아이디어를 보여줍니다
population is
[-1488564139, -1510380623, -1980218182, -354029751, -564386445, -57285541, -753388655, -775519772, 1538266464, 2006248253, 287039585, 386398836, 435619764, 48109172, 580324150, 64275438, 860615531]
sample is
[-57285541, -753388655, 386398836]
업데이트
위의 프로그램을하지만,주의를 가지고 - 이후 그 세트를 통해 걸어 다니는 샘플이 인 확률은 확률로입니다.210 반환 된 sample
은 오늘의 행운에 따라 지정된 것보다 더 많거나 많은 샘플을 가지고 있습니다. 이 문제는, 그러나, 절차의 약간의 변화, 약간 다른 방법 서명 사용 으로 해결할 수 있습니다 오버 샘플링의
/**
* Pick some samples from a population
* @param population
* @param sampleSize - number of samples
* @param exactSize - a boolean to control whether or not
* the returned sample list must be of the exact size as
* specified.
* @return
*/
private static <T>
List<T> sampleFromPopulation(Set<T> population
, int sampleSize
, boolean exactSize);
방지를 인구를 통해 하나 개의 반복에서
, 우리 샘플 비트, 그리고 나서 우리가 너무 많은 것을 가지고 있다면 결국 샘플을 버립니다. 그
참고 또한 언더의
방지, 심지어 오버 샘플링과 인구를 통해 하나의 반복의 끝에서, 우리는 여전히 원하는 미만의 샘플을 얻을, 비 - 제로 확률 있다 . 그럴 경우 (있을 법하지 않음) 재귀 적으로 두 번째 시도와 동일한 방법으로 을 다시 호출합니다. (이 재귀는 매우 그와는 달리하기 때문에 하나의 이 방법으로 반복 순환 통화, 종료 접근 확률을 가지고, 우리는 지속적으로 언더를 얻을.)
는 다음 코드는 새로운 sampleFromPopulation()
방법을 구현합니다
private static <T>
List<T> sampleFromPopulation(Set<T> population
, int sampleSize
, boolean exactSize) {
int popSize = population.size();
double sampleProb = ((double) sampleSize)/popSize;
final double OVER_SAMPLING_MULIT = 1.2;
if (exactSize) {
/*
* Oversampling to enhance of chance of getting enough
* samples (if we then have too many, we will drop them
* later)
*/
sampleProb = sampleProb * OVER_SAMPLING_MULIT;
}
List<T> sample = new LinkedList<>(); // linked list for fast removal
Iterator<T> iter = population.iterator();
while (iter.hasNext()) {
T element = iter.next();
if (random.nextFloat()<sampleProb) {
/*
* Lucky Draw!
*/
sample.add(element);
}
}
int samplesTooMany = sample.size() - sampleSize;
if (!exactSize || samplesTooMany==0) {
return sample;
} else if (samplesTooMany>0) {
Set<Integer> indexesToRemoveAsSet = new HashSet<>();
for (int i=0; i<samplesTooMany;) {
int candidate = random.nextInt(sample.size());
if (indexesToRemoveAsSet.add(candidate)) {
/*
* add() returns true if candidate was not
* previously in the set
*/
i++; // proceed to draw next index
}
}
List<Integer> indexesToRemoveAsList
= new ArrayList<>(indexesToRemoveAsSet);
Collections.sort(indexesToRemoveAsList
, (i1, i2) -> i2.intValue() - i1.intValue()); // desc order
/*
* Now we drop from the tail of the list
*/
for (Integer index : indexesToRemoveAsList) {
sample.remove((int) index); // remove by index (not by element)
}
return sample;
} else {
/*
* we were unluckly that we oversampling we still
* get less samples than specified, so here we call
* this very same method again recursively
*/
return sampleFromPopulation(population, sampleSize, exactSize);
}
}
을
세트가 소트 세트 (예 :'TreeSet')가 아니면, "nth"라는 개념이 없습니다. 반면에'TreeSet'은 인덱스 목록을 제공하지 않습니다. 어쨌든 반복을 필요로합니다 (링크 된 목록의 n 번째 요소에 액세스하는 것이 반복을 필요로합니다). 따라서 반복 방법을 계속 사용하거나 추적 할 수 있습니다. 요소는 설정된 수정 작업 중 n 번째입니다. – Thomas
사용자 정의 compareTo, equals 및 hashCode 메소드가있는 특수 키를 사용하여 얻을 수있는 방법이 있습니까? – gyurix
그것이 가능할지라도 (거의 모든 것이 어쨌든 가능합니다.) 실제로 아무것도 얻지 못할 것입니다 : 트리가 역전되었는지 여부에 관계없이 루트 노드에 해당하는 인덱스의 정확한 레이아웃을 알아야합니다. 또는 등등. 그리고 당신은 룩업 단계를 추적하고 그것으로부터 현재의 인덱스를 계산해야 할 것입니다. - 반복 할 때 당신이하는 것처럼 더 많은 것을하지 않으면 결국 많은 것을 할 것입니다. 다른 한편으로는 이와 같은 특수 키를 사용하면 오류가 발생하기 쉽고 실제로 나무를 부러 뜨릴 수 있으므로 그렇게하지 않을 것입니다. – Thomas