NumPy o SciPy para calcular la mediana ponderada

Estoy tratando de automatizar un proceso que realiza JMP (Analizar-> Distribución, ingresando la columna A como el “valor Y”, utilizando las columnas subsiguientes como el valor del “peso”). En JMP, debe hacer esto una columna a la vez; me gustaría usar Python para recorrer todas las columnas y crear una matriz que muestre, por ejemplo, la mediana de cada columna.

Por ejemplo, si la matriz de masa es [0, 10, 20, 30], y la matriz de peso para la columna 1 es [30, 191, 9, 0], la mediana ponderada de la matriz de masa debería ser 10. Sin embargo, I No estoy seguro de cómo llegar a esta respuesta.

Hasta ahora he

  1. importó el csv que muestra los pesos como una matriz, enmascarando los valores de 0, y
  2. creó una matriz del “valor Y” con la misma forma y tamaño que la matriz de pesos (113×32). No estoy completamente seguro de que deba hacer esto, pero pensé que sería más fácil que un bucle for con el fin de ponderar.

No estoy seguro de a dónde ir exactamente desde aquí. Básicamente, el “valor Y” es un rango de masas, y todas las columnas de la matriz representan el número de puntos de datos encontrados para cada masa. Necesito encontrar la masa mediana, según la frecuencia con la que se informaron.

No soy un experto en Python o en estadísticas, así que si omití algún detalle que pudiera ser útil, ¡hágamelo saber!

Actualización: aquí hay un código para lo que he hecho hasta ahora:

#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() 

Lo que podemos hacer, si entendí tu problema correctamente. Es para resumir las observaciones, dividir por 2 nos daría el número de observación correspondiente a la mediana. A partir de ahí tenemos que averiguar qué observación fue este número.

Un truco aquí es calcular las sums de observación con np.cumsum. Lo que nos da una sum acumulada en ejecución.

Ejemplo:
np.cumsum([1,2,3,4]) -> [ 1, 3, 6, 10]
Cada elemento es la sum de todos los elementos anteriores y de sí mismo. Tenemos 10 observaciones aquí. entonces la media sería la 5ª observación. (Obtenemos 5 dividiendo el último elemento por 2).
Ahora, observando el resultado de la acumulación, podemos ver fácilmente que esa debe ser la observación entre el segundo y el tercer elemento (observación 3 y 6).

Así que todo lo que tenemos que hacer, es averiguar el índice de dónde encajará la mediana (5).
np.searchsorted hace exactamente lo que necesitamos. Encontrará el índice para insertar elementos en una matriz, de modo que permanezca ordenado.

El código para hacerlo así:

 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)) 

La salida será:

 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]] 

Compartiendo un código con el que conseguí una mano. Esto le permite ejecutar estadísticas en cada columna de una hoja de cálculo de 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")