methods.py 3.95 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Nov 26 17:42:33 2019

@author: brandt
"""
import random
import numpy as np
from helpers import ParticleBinSorter

Josef Brandt's avatar
Josef Brandt committed
12

13 14 15 16 17 18
class SubsamplingMethod(object):
    def __init__(self, particleConatainer, desiredFraction: float = 0.2):
        super(SubsamplingMethod, self).__init__()
        self.particleContainer = particleConatainer
        self.fraction = desiredFraction

Josef Brandt's avatar
Josef Brandt committed
19 20 21 22 23 24 25 26
    @property
    def label(self) -> str:
        """
        A specific label that can be used for plots, for instance.
        :return:
        """
        raise NotImplementedError

Josef Brandt's avatar
Josef Brandt committed
27 28 29 30 31 32 33
    def apply_subsampling_method(self) -> tuple:
        """
        Takes all particles from the supplied particle conatiner and returns a new list of particles that
        were measured by applying that subsampling procedure. Also, the actualy measured fraction is returned.
        (The desired fraction may not always be achievable)
        :returns actuallyMeasuredFraction, listOfSubParticles:
        """
34 35 36
        raise NotImplementedError


Josef Brandt's avatar
Josef Brandt committed
37
class RandomSampling(SubsamplingMethod):
Josef Brandt's avatar
Josef Brandt committed
38 39 40 41
    @property
    def label(self) -> str:
        return 'Random Subsampling'

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
    def apply_subsampling_method(self):
        numOrigParticles = len(self.particleContainer.particles)
        numParticles = self._get_number_of_random_particles(numOrigParticles)
        subParticles = random.sample(self.particleContainer.particles, numParticles)
        return self.fraction, subParticles
    
    def _get_number_of_random_particles(self, numTotalParticles):
        return np.int(np.ceil(numTotalParticles * self.fraction))

        
class IvlevaSubsampling(SubsamplingMethod):
    def __init__(self, particleContainer, sigma=1.65, mpFraction=0.01, errorMargin=0.1):
        super(IvlevaSubsampling, self).__init__(particleContainer)
        self.sigma = sigma
        self.estimatedMPFraction = mpFraction
        self.errorMargin = errorMargin
Josef Brandt's avatar
Josef Brandt committed
58 59 60 61 62

    @property
    def label(self) -> str:
        return 'Random fraction, Anger et al.'

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
    def apply_subsampling_method(self):
        N = self.particleContainer.getNumberOfParticles()
        numParticlesMeasured = self._get_ivleva_fraction(N)
        subParticles = random.sample(self.particleContainer.particles, numParticlesMeasured)
        fractionMeasured = numParticlesMeasured/N
        return fractionMeasured, subParticles
        
    def _get_ivleva_fraction(self, N):
        P = self.estimatedMPFraction
        e = P * self.errorMargin            
        numParticlesMeasured = np.ceil(P*(1 - P) / (e**2/self.sigma**2 + P*(1-P)/N))
        return np.int(numParticlesMeasured)
    

class SizeBinFractioning(SubsamplingMethod):
    def __init__(self, particleConatiner, desiredfraction: float = 0.2):
        super(SizeBinFractioning, self).__init__(particleConatiner, desiredfraction)
        self.sorter: ParticleBinSorter = ParticleBinSorter()
Josef Brandt's avatar
Josef Brandt committed
81 82 83 84 85

    @property
    def label(self) -> str:
        return 'SizeBin Random Subsampling'

86 87 88 89 90 91 92 93 94 95 96 97 98
    def apply_subsampling_method(self):
        subParticlesPerBin: list = self._get_subParticles_per_bin(self.particleContainer.particles)
        subParticles: list = []
        for subParticleList in subParticlesPerBin:
            for particle in subParticleList:
                subParticles.append(particle)
        return self.fraction, subParticles
    
    def _get_subParticles_per_bin(self, particleList: list):
        particlesInBins: list = self.sorter.sort_particles_into_bins(particleList)
        subParticlesPerBin: list = []
        for particles in particlesInBins:
            numParticlesInBin: int = len(particles)
Josef Brandt's avatar
Josef Brandt committed
99
            numSubParticlesPerBin: int = np.int(np.round(numParticlesInBin * self.fraction))
100 101 102 103 104 105 106
            if numSubParticlesPerBin == 0 and numParticlesInBin > 0:
                numSubParticlesPerBin = 1

            subParticlesInBin: list = random.sample(particles, numSubParticlesPerBin)
            subParticlesPerBin.append(subParticlesInBin)
            
        return subParticlesPerBin