2014-09-29 41 views
6

Tôi có một dataframe trông như thế này:Python: trọng số thuật toán trung bình với gấu trúc

Out[14]: 
    impwealth indweight 
16  180000  34.200 
21  384000  37.800 
26  342000  39.715 
30 1154000  44.375 
31  421300  44.375 
32 1210000  45.295 
33 1062500  45.295 
34 1878000  46.653 
35  876000  46.653 
36  925000  53.476 

tôi muốn để tính trung bình có trọng số của các cột impwealth sử dụng các trọng số tần số trong indweight. mã giả của tôi trông như thế này:

# Sort `impwealth` in ascending order 
df.sort('impwealth', 'inplace'=True) 

# Find the 50th percentile weight, P 
P = df['indweight'].sum() * (.5) 

# Search for the first occurrence of `impweight` that is greater than P 
i = df.loc[df['indweight'] > P, 'indweight'].last_valid_index() 

# The value of `impwealth` associated with this index will be the weighted median 
w_median = df.ix[i, 'impwealth'] 

phương pháp này có vẻ vụng về, và tôi không chắc chắn đó là chính xác. Tôi đã không tìm thấy một cách xây dựng để làm điều này trong tham chiếu gấu trúc. Cách tốt nhất để đi về việc tìm kiếm trung bình có trọng số là gì?

+0

Bạn có chắc chắn mã giả của bạn là chính xác? 'df ['indweight']. sum() * (.5)' sẽ cho một giá trị '219' mà không có giá trị' indweight' nào của bạn vượt quá. Gọi 'df ['indweight']. Median()' cho 44.835 và 'mean()' cho 43.783 – EdChum

+0

Tôi nghĩ vậy .. 'df ['indweight']. Sum() * (.5)' nên tính số lượng các quan sát nằm dưới phân vị thứ 50 trong dữ liệu, vì 'indweight' là trọng số tần số. Vì vậy, nó có ý nghĩa rằng trung bình và trung bình của 'indweight' vượt quá tổng của nó. – svenkatesh

+0

@svenkatesh, bạn cần sử dụng '' .cumsum() '' của '' indweight'', không phải '' indweight''. Xem câu trả lời của tôi dưới đây, có lẽ. – prooffreader

Trả lời

7

Nếu bạn muốn làm điều này trong gấu trúc nguyên chất, dưới đây là một cách. Nó cũng không nội suy. (@svenkatesh, bạn bị mất tích tổng tích lũy trong giả của bạn)

df.sort_values('impwealth', inplace=True) 
cumsum = df.indweight.cumsum() 
cutoff = df.indweight.sum()/2.0 
median = df.impwealth[cumsum >= cutoff].iloc[0] 

này đưa ra một trung bình 925000.

5

Bạn đã thử gói wqantiles chưa? Tôi chưa bao giờ sử dụng nó trước đây, nhưng nó có một chức năng trung bình có trọng số mà dường như đưa ra ít nhất một câu trả lời hợp lý (có thể bạn sẽ muốn kiểm tra lại rằng nó đang sử dụng cách tiếp cận bạn mong đợi).

In [12]: import weighted 

In [13]: weighted.median(df['impwealth'], df['indweight']) 
Out[13]: 914662.0859091772 
+2

typo: wqantiles -> wquantiles – Jaan

+1

Cá nhân, tôi hơi cảnh giác với việc cài đặt một gói mà một vài dòng mã sẽ làm, nhưng nếu bạn cần trung gian có trọng số nội suy, có lẽ đây là cách tiếp cận tốt nhất. – prooffreader

1

Bạn cũng có thể sử dụng chức năng này mà tôi đã viết cho cùng một mục đích.

Lưu ý: trọng số sử dụng nội suy ở cuối để chọn 0,5 quantile (bạn có thể nhìn vào mã chính mình)

chức năng viết của tôi chỉ trả về một bounding 0,5 cân.

import numpy as np 

def weighted_median(values, weights): 
    ''' compute the weighted median of values list. The 
weighted median is computed as follows: 
    1- sort both lists (values and weights) based on values. 
    2- select the 0.5 point from the weights and return the corresponding values as results 
    e.g. values = [1, 3, 0] and weights=[0.1, 0.3, 0.6] assuming weights are probabilities. 
    sorted values = [0, 1, 3] and corresponding sorted weights = [0.6,  0.1, 0.3] the 0.5 point on 
    weight corresponds to the first item which is 0. so the weighted  median is 0.''' 

    #convert the weights into probabilities 
    sum_weights = sum(weights) 
    weights = np.array([(w*1.0)/sum_weights for w in weights]) 
    #sort values and weights based on values 
    values = np.array(values) 
    sorted_indices = np.argsort(values) 
    values_sorted = values[sorted_indices] 
    weights_sorted = weights[sorted_indices] 
    #select the median point 
    it = np.nditer(weights_sorted, flags=['f_index']) 
    accumulative_probability = 0 
    median_index = -1 
    while not it.finished: 
     accumulative_probability += it[0] 
     if accumulative_probability > 0.5: 
      median_index = it.index 
      return values_sorted[median_index] 
     elif accumulative_probability == 0.5: 
      median_index = it.index 
      it.iternext() 
      next_median_index = it.index 
      return np.mean(values_sorted[[median_index, next_median_index]]) 
     it.iternext() 

    return values_sorted[median_index] 
#compare weighted_median function and np.median 
print weighted_median([1, 3, 0, 7], [2,3,3,9]) 
print np.median([1,1,0,0,0,3,3,3,7,7,7,7,7,7,7,7,7]) 
+0

chức năng trung bình có trọng số rất giống với câu trả lời được chấp nhận nếu bạn nhìn vào mã nhưng không nội suy ở cuối. – Ash

Các vấn đề liên quan