Car*_*Car 7 python statistics numpy scipy sas-jmp
我正在尝试自动化JMP所做的过程(“分析”->“分布”,将列A输入为“ Y值”,使用后续列作为“权重”值)。在JMP中,您必须一次完成一列-我想使用Python遍历所有列并创建一个数组,例如显示每列的中位数。
例如,如果质量数组为[0、10、20、30],列1的权重数组为[30、191、9、0],则质量数组的加权中位数应为10。我不确定如何得出这个答案。
到目前为止,我已经
我不确定从这里到底要去哪里。基本上,“ 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()
Run Code Online (Sandbox Code Playgroud)
mas*_*ers 11
由于这是 Google 上 NumPy 中加权中位数的热门搜索,因此我将添加我的最小函数来从两个数组中选择加权中位数,而不更改其内容,并且不对值的顺序进行任何假设(可能性很小)其他人来这里寻找相同的先决条件的快速配方)。
def weighted_median(values, weights):
i = np.argsort(values)
c = np.cumsum(weights[i])
return values[i[np.searchsorted(c, 0.5 * c[-1])]]
Run Code Online (Sandbox Code Playgroud)
使用argsort
可以让我们保持两个数组之间的对齐,而无需更改或复制它们的内容。将其扩展到任意数量的任意分位数应该是直接的。
更新
由于乍一看可能并不完全清楚扩展到任意分位数到底有多容易,因此代码如下:
def weighted_quantiles(values, weights, quantiles=0.5):
i = np.argsort(values)
c = np.cumsum(weights[i])
return values[i[np.searchsorted(c, np.array(quantiles) * c[-1])]]
Run Code Online (Sandbox Code Playgroud)
默认为中位数,但您可以传入任何分位数或分位数列表。返回类型相当于您传入的类型quantiles
,其中列表提升为 NumPy 数组。有了足够的均匀分布值,您确实可以很好地近似输入:
>>> weighted_quantiles(np.random.rand(10000), np.random.rand(10000), [0.01, 0.05, 0.25, 0.50, 0.75, 0.95, 0.99])
array([0.01235101, 0.05341077, 0.25355715, 0.50678338, 0.75697424,0.94962936, 0.98980785])
>>> weighted_quantiles(np.random.rand(10000), np.random.rand(10000), 0.5)
0.5036283072043176
>>> weighted_quantiles(np.random.rand(10000), np.random.rand(10000), [0.5])
array([0.49851076])
Run Code Online (Sandbox Code Playgroud)
更新2
在实际未观察到中位数/分位数的小数据集中,能够在两个观察值之间插入一个点可能很重要。在重量质量在两个值之间均分(或分位数/1分位数)的情况下,可以通过计算两个值之间的中点来相当容易地添加。由于需要条件,此函数始终返回 NumPy 数组,即使quantiles
是单个标量也是如此。输入现在也需要是 NumPy 数组(除了quantiles
可能仍然是单个数字)。
def weighted_quantiles_interpolate(values, weights, quantiles=0.5):
i = np.argsort(values)
c = np.cumsum(weights[i])
q = np.searchsorted(c, quantiles * c[-1])
return np.where(c[q]/c[-1] == quantiles, 0.5 * (values[i[q]] + values[i[q+1]]), values[i[q]])
Run Code Online (Sandbox Code Playgroud)
对于小于 2 的数组,此函数将失败(原始函数将处理非空数组)。
>>> weighted_quantiles_interpolate(np.array([2, 1]), np.array([1, 1]), 0.5)
array(1.5)
Run Code Online (Sandbox Code Playgroud)
请注意,在处理实际数据集时,不太可能需要此扩展,因为我们通常拥有(a)大型数据集和(b)实值权重,这使得最终完全位于分位数边缘的可能性非常大,并且可能是由于发生时的舍入错误。尽管如此,还是为了完整性而将其包括在内。
如果我正确理解您的问题,我们可以做什么。是将观察结果相加,除以 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))
Run Code Online (Sandbox Code Playgroud)
输出将是:
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]]
Run Code Online (Sandbox Code Playgroud)