NumPy或SciPy计算加权中位数

时间:2013-12-16 00:52:42

标签: python numpy scipy statistics sas-jmp

我正在尝试自动化JMP执行的过程(Analyze-> Distribution,输入A列作为“Y值”,使用后续列​​作为“权重”值)。在JMP中你必须一次只做一列 - 我想用Python循环遍历所有列并创建一个数组,显示每列的中位数。

例如,如果质量数组是[0,10,20,30],并且第1列的权重数组是[30,191,9,0],则质量数组的加权中值应为10。但是,我不确定如何得出这个答案。

到目前为止我已经

  1. 导入csv,将权重显示为数组,屏蔽值为0和
  2. 创建了一个“Y值”数组,其形状和大小与权重数组(113x32)相同。我不完全确定我需要这样做,但是为了加权,我觉得它比for循环更容易。
  3. 我不确定从这里到底要去哪里。基本上,“Y值”是质量范围,并且数组中的所有列表示为每个质量找到的数据点的数量。我需要根据报告的频率找到中位数质量。

    我不是Python或统计学专家,所以如果我省略任何有用的细节,请告诉我!

    更新:这是我迄今为止所做的一些代码:

    #Boilerplate & Import files
    import csv
    import scipy as sp
    from scipy import stats
    from scipy.stats import norm
    import numpy as np
    from numpy import genfromtxt
    import pandas as pd
    import matplotlib.pyplot as plt
    
    inputFile = '/Users/cl/prov.csv'
    origArray = genfromtxt(inputFile, delimiter = ",")
    nArray = np.array(origArray)
    dimensions = nArray.shape
    shape = np.asarray(dimensions)
    
    #Mask values ==0
    maTest = np.ma.masked_equal(nArray,0)
    
    #Create array of masses the same shape as the weights (nArray)
    fieldLength = shape[0]
    rowLength = shape[1]
    
    for i in range (rowLength):
        createArr = np.arange(0, fieldLength*10, 10)
        nCreateArr = np.array(createArr)
        massArr.append(nCreateArr)
        nCreateArr = np.array(massArr)
    nmassArr = nCreateArr.transpose()
    

3 个答案:

答案 0 :(得分:4)

如果我理解你的问题,我们能做什么。是总结观察,除以2将给出我们对应中位数的观测数。从那里我们需要弄清楚这个数字的观察结果。

这里的一个技巧是用np.cumsum计算观察总和。这给了我们一个累积的累计金额。

例:
 np.cumsum([1,2,3,4]) -> [ 1, 3, 6, 10]
每个元素是所有先前元素和自身的总和。我们这里有10个观测值。所以平均值将是第5次观察。 (我们将最后一个元素除以2得到5) 现在看一下cumsum结果,我们可以很容易地看出,必须是第二和第三元素之间的观察(观察3和6)。

所以我们需要做的就是找出中位数(5)适合的指数 np.searchsorted正是我们所需要的。它将找到将元素插入数组的索引,以便它保持排序。

这样做的代码如下:

import numpy as np
#my test data
freq_count = np.array([[30, 191, 9, 0], [10, 20, 300, 10], [10,20,30,40], [100,10,10,10], [1,1,1,100]])

c = np.cumsum(freq_count, axis=1) 
indices = [np.searchsorted(row, row[-1]/2.0) for row in c]
masses = [i * 10 for i in indices] #Correct if the masses are indeed 0, 10, 20,...

#This is just for explanation.
print "median masses is:",  masses
print freq_count
print np.hstack((c, c[:, -1, np.newaxis]/2.0))

输出将是:

median masses is: [10 20 20  0 30]  
[[ 30 191   9   0]  <- The test data
 [ 10  20 300  10]  
 [ 10  20  30  40]  
 [100  10  10  10]  
 [  1   1   1 100]]  
[[  30.   221.   230.   230.   115. ]  <- cumsum results with median added to the end.
 [  10.    30.   330.   340.   170. ]     you can see from this where they fit in.
 [  10.    30.    60.   100.    50. ]  
 [ 100.   110.   120.   130.    65. ]  
 [   1.     2.     3.   103.    51.5]]  

答案 1 :(得分:1)

分享我手中的一些代码。这允许您在Excel电子表格的每一列上运行统计信息。

import xlrd
import sys
import csv
import numpy as np
import itertools
from itertools import chain

book = xlrd.open_workbook('/filepath/workbook.xlsx')
sh = book.sheet_by_name("Sheet1")
ofile = '/outputfilepath/workbook.csv'

masses = sh.col_values(0, start_rowx=1)  # first column has mass
age = sh.row_values(0, start_colx=1)   # first row has age ranges

count = 1
mass = []
for a in ages:
    age.append(sh.col_values(count, start_rowx=1))
    count += 1

stats = []
count = 0    
for a in ages:
    expanded = []
    # create a tuple with the mass vector

    age_mass = zip(masses, age[count])
    count += 1
    # replicate element[0] for element[1] times
    expanded = list(list(itertools.repeat(am[0], int(am[1]))) for am in age_mass)

    #  separate into one big list
    medianlist = [x for t in expanded for x in t]

    # convert to array and mask out zeroes
    npa = np.array(medianlist)
    npa = np.ma.masked_equal(npa,0)

    median = np.median(npa)
    meanMass = np.average(npa)
    maxMass = np.max(npa)
    minMass = np.min(npa)
    stdev = np.std(npa)

    stats1 = [median, meanMass, maxMass, minMass, stdev]
    print stats1

    stats.append(stats1)

np.savetxt(ofile, (stats), fmt="%d") 

答案 2 :(得分:0)

wquantiles是一个小型python软件包,可以完全满足您的需求。它只是在后台使用np.cumsum()和np.interp()。