복붙노트

[PYTHON] numpy를 사용하는 가중 백분위 수

PYTHON

numpy를 사용하는 가중 백분위 수

가중 백분위를 계산하기 위해 numpy.percentile 함수를 사용하는 방법이 있습니까? 아니면 가중치 백분위를 계산하는 파이썬 함수를 알고있는 사람이 있습니까?

감사!

해결법

  1. ==============================

    1.안타깝게도 numpy는 모든 것에 대해 가중 함수를 내장하지 않지만 언제나 함께 사용할 수 있습니다.

    안타깝게도 numpy는 모든 것에 대해 가중 함수를 내장하지 않지만 언제나 함께 사용할 수 있습니다.

    def weight_array(ar, weights):
         zipped = zip(ar, weights)
         weighted = []
         for i in zipped:
             for j in range(i[1]):
                 weighted.append(i[0])
         return weighted
    
    
    np.percentile(weight_array(ar, weights), 25)
    
  2. ==============================

    2.여기에 제가 사용하고있는 코드가 있습니다. 그것은 최적의 것이 아닙니다 (나는 numpy로 쓸 수 없습니다). 그러나 여전히 받아 들여진 해결책보다 훨씬 빠르고 신뢰할 수 있습니다.

    여기에 제가 사용하고있는 코드가 있습니다. 그것은 최적의 것이 아닙니다 (나는 numpy로 쓸 수 없습니다). 그러나 여전히 받아 들여진 해결책보다 훨씬 빠르고 신뢰할 수 있습니다.

    def weighted_quantile(values, quantiles, sample_weight=None, values_sorted=False, old_style=False):
        """ Very close to numpy.percentile, but supports weights.
        NOTE: quantiles should be in [0, 1]!
        :param values: numpy.array with data
        :param quantiles: array-like with many quantiles needed
        :param sample_weight: array-like of the same length as `array`
        :param values_sorted: bool, if True, then will avoid sorting of initial array
        :param old_style: if True, will correct output to be consistent with numpy.percentile.
        :return: numpy.array with computed quantiles.
        """
        values = numpy.array(values)
        quantiles = numpy.array(quantiles)
        if sample_weight is None:
            sample_weight = numpy.ones(len(values))
        sample_weight = numpy.array(sample_weight)
        assert numpy.all(quantiles >= 0) and numpy.all(quantiles <= 1), 'quantiles should be in [0, 1]'
    
        if not values_sorted:
            sorter = numpy.argsort(values)
            values = values[sorter]
            sample_weight = sample_weight[sorter]
    
        weighted_quantiles = numpy.cumsum(sample_weight) - 0.5 * sample_weight
        if old_style:
            # To be convenient with numpy.percentile
            weighted_quantiles -= weighted_quantiles[0]
            weighted_quantiles /= weighted_quantiles[-1]
        else:
            weighted_quantiles /= numpy.sum(sample_weight)
        return numpy.interp(quantiles, weighted_quantiles, values)
    

    예 :

    배열 ([1., 3.2, 9.])

    배열 ([1., 3.2, 9.])

  3. ==============================

    3.첫 번째 정렬 및 보간을 통한 빠른 솔루션 :

    첫 번째 정렬 및 보간을 통한 빠른 솔루션 :

      def weighted_percentile(data, percents, weights=None):
          ''' percents in units of 1%
          weights specifies the frequency (count) of data.
          '''
          if weights is None:
            return np.percentile(data, percents)
          ind=np.argsort(data)
          d=data[ind]
          w=weights[ind]
          p=1.*w.cumsum()/w.sum()*100
          y=np.interp(percents, p, d)
          return y
    
  4. ==============================

    4.추가 (독창적 인) 답변에 대한 사과 (@ nayyarv에 대한 의견을 말할 수있는 담당자가 충분하지 않음). 그의 솔루션은 나를 위해 일했습니다. (즉, np.percentage의 기본 동작을 복제합니다.)하지만 원래의 np.percentage가 어떻게 작성되었는지 단서가있는 for 루프를 제거 할 수 있다고 생각합니다.

    추가 (독창적 인) 답변에 대한 사과 (@ nayyarv에 대한 의견을 말할 수있는 담당자가 충분하지 않음). 그의 솔루션은 나를 위해 일했습니다. (즉, np.percentage의 기본 동작을 복제합니다.)하지만 원래의 np.percentage가 어떻게 작성되었는지 단서가있는 for 루프를 제거 할 수 있다고 생각합니다.

    def weighted_percentile(a, q=np.array([75, 25]), w=None):
        """
        Calculates percentiles associated with a (possibly weighted) array
    
        Parameters
        ----------
        a : array-like
            The input array from which to calculate percents
        q : array-like
            The percentiles to calculate (0.0 - 100.0)
        w : array-like, optional
            The weights to assign to values of a.  Equal weighting if None
            is specified
    
        Returns
        -------
        values : np.array
            The values associated with the specified percentiles.  
        """
        # Standardize and sort based on values in a
        q = np.array(q) / 100.0
        if w is None:
            w = np.ones(a.size)
        idx = np.argsort(a)
        a_sort = a[idx]
        w_sort = w[idx]
    
        # Get the cumulative sum of weights
        ecdf = np.cumsum(w_sort)
    
        # Find the percentile index positions associated with the percentiles
        p = q * (w.sum() - 1)
    
        # Find the bounding indices (both low and high)
        idx_low = np.searchsorted(ecdf, p, side='right')
        idx_high = np.searchsorted(ecdf, p + 1, side='right')
        idx_high[idx_high > ecdf.size - 1] = ecdf.size - 1
    
        # Calculate the weights 
        weights_high = p - np.floor(p)
        weights_low = 1.0 - weights_high
    
        # Extract the low/high indexes and multiply by the corresponding weights
        x1 = np.take(a_sort, idx_low) * weights_low
        x2 = np.take(a_sort, idx_high) * weights_high
    
        # Return the average
        return np.add(x1, x2)
    
    # Sample data
    a = np.array([1.0, 2.0, 9.0, 3.2, 4.0], dtype=np.float)
    w = np.array([2.0, 1.0, 3.0, 4.0, 1.0], dtype=np.float)
    
    # Make an unweighted "copy" of a for testing
    a2 = np.repeat(a, w.astype(np.int))
    
    # Tests with different percentiles chosen
    q1 = np.linspace(0.0, 100.0, 11)
    q2 = np.linspace(5.0, 95.0, 10)
    q3 = np.linspace(4.0, 94.0, 10)
    for q in (q1, q2, q3):
        assert np.all(weighted_percentile(a, q, w) == np.percentile(a2, q))
    
  5. ==============================

    5.weighted 백분위가 무엇인지 알지는 못하지만 @Joan Smith의 대답에서 보면 ar의 모든 요소를 ​​반복하면 numpy.repeat ()를 사용할 수 있습니다.

    weighted 백분위가 무엇인지 알지는 못하지만 @Joan Smith의 대답에서 보면 ar의 모든 요소를 ​​반복하면 numpy.repeat ()를 사용할 수 있습니다.

    import numpy as np
    np.repeat([1,2,3], [4,5,6])
    

    결과는 다음과 같습니다.

    array([1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3])
    
  6. ==============================

    6.내 필요에이 기능을 사용합니다.

    내 필요에이 기능을 사용합니다.

    def quantile_at_values(values, population, weights=None):
        values = numpy.atleast_1d(values).astype(float)
        population = numpy.atleast_1d(population).astype(float)
        # if no weights are given, use equal weights
        if weights is None:
            weights = numpy.ones(population.shape).astype(float)
            normal = float(len(weights))
        # else, check weights                  
        else:                                           
            weights = numpy.atleast_1d(weights).astype(float)
            assert len(weights) == len(population)
            assert (weights >= 0).all()
            normal = numpy.sum(weights)                    
            assert normal > 0.
        quantiles = numpy.array([numpy.sum(weights[population <= value]) for value in values]) / normal
        assert (quantiles >= 0).all() and (quantiles <= 1).all()
        return quantiles
    

    quantile 대신 백분위 수가 필요한 경우 결과에 100을 곱하십시오.

  7. ==============================

    7.의견에서 언급했듯이 단순히 float 가중치에서는 값을 반복 할 수 없으며 매우 큰 데이터 집합에서는 실용적이지 않습니다. 여기에 가중 백분위 수를 나타내는 라이브러리가 있습니다. http://www.google.com/intl/ko 그것은 나를 위해 일했습니다.

    의견에서 언급했듯이 단순히 float 가중치에서는 값을 반복 할 수 없으며 매우 큰 데이터 집합에서는 실용적이지 않습니다. 여기에 가중 백분위 수를 나타내는 라이브러리가 있습니다. http://www.google.com/intl/ko 그것은 나를 위해 일했습니다.

  8. ==============================

    8.

    def weighted_percentile(a, percentile = np.array([75, 25]), weights=None):
        """
        O(nlgn) implementation for weighted_percentile.
        """
        percentile = np.array(percentile)/100.0
        if weights is None:
            weights = np.ones(len(a))
        a_indsort = np.argsort(a)
        a_sort = a[a_indsort]
        weights_sort = weights[a_indsort]
        ecdf = np.cumsum(weights_sort)
    
        percentile_index_positions = percentile * (weights.sum()-1)+1
        # need the 1 offset at the end due to ecdf not starting at 0
        locations = np.searchsorted(ecdf, percentile_index_positions)
    
        out_percentiles = np.zeros(len(percentile_index_positions))
    
        for i, empiricalLocation in enumerate(locations):
            # iterate across the requested percentiles 
            if ecdf[empiricalLocation-1] == np.floor(percentile_index_positions[i]):
                # i.e. is the percentile in between 2 separate values
                uppWeight = percentile_index_positions[i] - ecdf[empiricalLocation-1]
                lowWeight = 1 - uppWeight
    
                out_percentiles[i] = a_sort[empiricalLocation-1] * lowWeight + \
                                     a_sort[empiricalLocation] * uppWeight
            else:
                # i.e. the percentile is entirely in one bin
                out_percentiles[i] = a_sort[empiricalLocation]
    
        return out_percentiles
    

    이것은 내 기능이며, 동일한 동작을 제공합니다.

    np.percentile(np.repeat(a, weights), percentile)
    

    메모리 오버 헤드가 적습니다. np.percentile은 O (n) 구현이므로 작은 가중치의 경우 더 빠를 수도 있습니다. 그것은 모든 엣지 케이스를 분류 해 놓았습니다. 정확한 해결책입니다. 위의 보간 답변은 가중치가 1 인 경우를 제외하고 대부분의 경우 단계 일 때 선형이라고 가정합니다.

    무게 [3, 11, 7]로 데이터 [1,2,3]가 있고 25 % 백분위 수를 원한다고 가정 해보십시오. 내 ecdf는 [3, 10, 21]이 될 것이며 5 번째 값을 찾고 있습니다. 보간법은 [3,1]과 [10,2]가 일치하는 것으로보고 보간법을 적용하여 2 번째 빈에 완전히 있음에도 불구하고 1.28을 내 보냅니다.

  9. ==============================

    9.여기 내 해결책 :

    여기 내 해결책 :

    def my_weighted_perc(data,perc,weights=None):
        if weights==None:
            return nanpercentile(data,perc)
        else:
            d=data[(~np.isnan(data))&(~np.isnan(weights))]
            ix=np.argsort(d)
            d=d[ix]
            wei=weights[ix]
            wei_cum=100.*cumsum(wei*1./sum(wei))
            return interp(perc,wei_cum,d)
    

    단순히 데이터의 가중 CDF를 계산 한 다음 가중 백분위 수를 계산하는 데 사용합니다.

  10. from https://stackoverflow.com/questions/21844024/weighted-percentile-using-numpy by cc-by-sa and MIT license