¿Fórmula para restar el promedio de un subconjunto de una columna de datos?Estoy buscando una forma de tomar un subconjunto de una tabla de datos que usa solo filas que coinciden con una condición específica y restar la media de esas filas de una columna.
Por ejemplo, usando el conjunto de datos Big Class, digamos que quiero crear una nueva columna que muestre "Diferencia de altura entre este estudiante y el promedio de 14 años del mismo sexo".
La forma en que sé cómo hacer esto es agregando una segunda tabla, usando Tablas -> Resumen -> Estadísticas: Media (altura), Grupo: sexo, Subgrupo: edad. Luego puedo Tabla -> Actualizar: Clase grande por (sexo), Coincidir columnas: sexo = sexo, y eso agregará varias columnas para Media (altura, [edad]). Entonces puedo crear una nueva columna "Altura delta vs 14 años del mismo sexo" que es: altura -: Media (altura, 14).
Mi pregunta: ¿hay alguna forma de hacerlo sin crear una tabla adicional y la columna adicional (por ejemplo, "Media (altura, 14)")? Parece que Col Mean (x, byVar) está cerca de proporcionar esta funcionalidad, pero carece de la funcionalidad para seleccionar un grupo diferente; por ejemplo, podría usar: height - Col Mean (: height,: age,: sex) para encontrar el delta entre el estudiante X y el estudiante promedio de su propio sexo y altura, pero no sé si hay una manera de especificar en Col Mean que solo quiero considerar filas con age = 14, en lugar de usar el valor de edad asociado con esa fila.
Hago este tipo de normalización con mucha frecuencia, por lo que cualquier cosa para hacerlo más rápido y más fácil sería enormemente apreciado.
Tabla de datosRe: ¿fórmula para restar el promedio de un subconjunto de una columna de datos?¡Hola, MarkJSchwab!
Por supuesto, hay una forma de hacer lo que desee.¡JSL te hará libre!
Escribí un script simple que usa principalmente la capacidad de JSL para escribir un script para ti.Intentalo:
// Title: Bigclass Normalization Script for JMP User Community discussion
// Purpose: Demonstrate how to write a very basic script to do "normalizations"
Names Default To Here( 1 );
Bigclass_dt = Open( "$SAMPLE_DATA\Big Class.jmp" );
BigclassSummary_dt = bigclass_dt << Summary( Group( :age, :sex ), Mean( :height ) );
BigclassSummary_dt << Select Where( :Age != 14 ) << Delete Rows;
Bigclass_dt << Join(
With( BigclassSummary_dt ),
Select( :name, :age, :sex, :height ),
SelectWith( :Name( "Mean(height)" ) ),
By Matching Columns( :sex = :sex ),
Drop multiples( 0, 0 ),
Include Nonmatches( 0, 0 ),
Preserve main table order( 1 ),
Output Table( "NormedBigclass by AgeGender" )
);
BigclassJoin_dt = Data Table( "NormedBigclass by AgeGender" ) << New Column( "Normalized",
numeric,
continuous,
Formula( :Name( "height" ) - :Name( "Mean(height)" ) ),
evalFormula
);
Close( BigclassSummary_dt, NoSave );
Hice una tabla de resumen separada y luego la cerré, pero no tienes que hacerlo de esa manera.
Por supuesto, existen formas más sofisticadas de escribir un script como este, especialmente porque todas las cláusulas "where" están codificadas de forma rígida y es posible que tenga problemas con este script si su tabla de datos es grande, pero, aún así, JSL será su ruta hacia la productividad.¡Hay varios recursos excelentes para aprender JSL!
¡Buena suerte!
Re: ¿fórmula para restar el promedio de un subconjunto de una columna de datos?Hola @MarkJSchwab ,
Hay una forma sencilla de hacer esto usando Col Mean () que no es obvia hasta que la ve. Col Mean () toma un argumento de columna de frecuencia:

Por lo general, esto es para cuando necesita ponderar con otra columna. Pero, en su ejemplo, ¿qué pasaría si pudiéramos ponderar los valores de Edad == 14 como 1 y todos los demás valores como 0? Eso nos daría una media de solo aquellos individuos donde Edad == 14. Podemos hacerlo directamente en la fórmula:
Col Mean( :height, <<FREQ></FREQ>

Esto devolverá:

Ahora, para su pregunta específica, centrándose con respecto a esta media específica desde la altura, podemos envolver eso en la fórmula de la manera habitual:
:height - (Col Mean( :height, <<FREQ></FREQ>


¡Espero que esto ayude!
@Julian
Re: ¿fórmula para restar el promedio de un subconjunto de una columna de datos?Hola @Julian , Gracias por la sugerencia. Desafortunadamente, cuando pego esa fórmula exacta
Col Mean( :height, <<FREQ></FREQ>
en mi clase grande, devuelve 62,55 (es decir, la media general de Col sin seleccionar edad = 14) en lugar del valor correcto que está viendo de 64,166.
Incluso puedo descargar su archivo adjunto, y los valores correctos aparecen en la columna "Centrado con respecto a la media a la edad == 14". Pero si hago una nueva columna en esa tabla con la misma fórmula exacta, devuelve valores diferentes (mostrando la [altura] - [altura promedio general], en lugar de mostrar correctamente [altura] - [altura promedio de 14yos]).
Estoy usando JMP Pro 14.3.0. ¿Alguna idea sobre cómo puedo hacer que mi salida coincida con la suya?
Y una pregunta más, en su hoja si agrega un byVar adicional de: sexo (para la fórmula total ": altura - (Col media (: altura,: sexo, << Frec (: edad == 14)))" ¿hace eso restar la estatura promedio de los niños de 14 años de los niños y la estatura promedio de las niñas de 14 años de las niñas?
Re: ¿fórmula para restar el promedio de un subconjunto de una columna de datos?Hola @MarkJSchwab ,
Parece que << Freq se agregó como un argumento opcional en JMP 15, por lo que para versiones anteriores de JMP deberá hacer algo más.
Aquí hay una solución del asistente de jmp @brady_brady :
:height - Mean( :height[(:height << get datatable) << get rows where( :age == 14 )] )

Vale la pena tomarse un momento para analizar esta fórmula porque hay algunos métodos que apuesto a que le resultará útil usarlos más adelante.
(:height << get datatable) << get rows where( :age == 14 )
devolverá la matriz de entradas de fila en la que: edad == 14. Es importante destacar que puede modificar la función obtener filas donde () para que coincida con la búsqueda que desee, incluida la segunda pregunta que creo que tiene de incluir otra variable. Por ejemplo:
(:height << get datatable) << get rows where( :age == 14 & :sex == "F"

Ahora que tenemos una matriz de filas que coincide con su condición, Brady usa esta matriz para subíndice: altura.
height[(:height << get datatable) << get rows where( :age == 14 & :sex == "F" )]

Esto devolverá la matriz de los valores de: altura para cada una de esas filas, en este caso, las alturas de las alumnas de 14 años: [61, 62, 65, 63, 62]
Finalmente, la función Mean () se envuelve alrededor de esta matriz, que devuelve la media que necesita para calcular su variable centrada:
mean(:height[(:height << get datatable) << get rows where( :age == 14 & :sex == "F" )])

Esta solución es más flexible, tolerante con los datos faltantes y funciona para versiones anteriores de jmp, por lo que creo que es una mejor solución. Gracias, @brady_brady !
@Julian
Re: ¿fórmula para restar el promedio de un subconjunto de una columna de datos?Hola @Julian ¡Gracias de nuevo por la ayuda!
Una última arruga: idealmente me gustaría que la edad media de las niñas de 14 años se reste de las niñas, y que la edad promedio de los niños de 14 años se reste de los niños. (En su ejemplo, está restando la edad de niña de 14 años tanto de niños como de niñas).
(Me doy cuenta de que en este caso específico con solo M / F sería fácil usar un condicional y decir "Si: sexo == 'F', entonces use esta fórmula, si: sexo == 'M' luego modifique la fórmula para say {mean (: height [(: height << get datatable) << get rows where (: age == 14 &: sex == "M")])} "pero en mis casos de uso más generales puedo tener un un gran número de grupos y condicionales anidados se volverían difíciles de manejar).
¿Alguna forma sencilla de lograrlo?
Re: ¿fórmula para restar el promedio de un subconjunto de una columna de datos?Solo necesita expandir la fórmula para manejar tanto hombres como mujeres
If( :sex == "F",
:height - Mean( :height[(:height << get datatable) << get rows where( :age == 14 & :sex == "F" )] ),
:height - Mean( :height[(:height << get datatable) << get rows where( :age == 14 & :sex == "M" )] )
)
Re: ¿fórmula para restar el promedio de un subconjunto de una columna de datos?Hola @MarkJSchwab ,
Sí, puedo ver cómo envolver esto en condicionales podría no ser ideal para muchos casos. Aquí hay una modificación a @brady_brady Solución que debería funcionar (tabla adjunta):

testVal = :sex;
:height - Mean( :height[(:height << get datatable) << get rows where( :age == 14 & :sex == testVal )] );
En este caso, tomamos el valor de: sex para la fila actual, lo guardamos en una variable, testVal. Luego, cuando evaluamos la función de centrado, podemos probar el uso de ese valor en la función obtener filas donde ().
Aquí está la tabla con una columna de solo las filas seleccionadas por esta función Get Rows Where ():

Como puede ver, todas las filas usan la edad 14 como subconjunto, pero qué subconjunto de sexo está determinado por los valores de fila actuales de sex. Debe adaptarse fácilmente a diferentes niveles de complejidad.
@Julian