¿Fórmula para restar el promedio de un subconjunto de una columna de datos?Estoy buscando una manera 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 -> Actualización: Clase grande por (sexo), Coincidir columnas: sexo = sexo, y eso agregará varias columnas para Media (altura, [edad]). Luego puedo crear una nueva columna "Altura delta frente a 14 años del mismo sexo" que es: altura -: Media (altura, 14).
Mi pregunta: ¿hay alguna manera 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 Significa que solo quiero considerar filas con edad = 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 sencillo sería enormemente apreciada.
Combinación y limpieza de datosRe: ¿Fórmula para restar el promedio de un subconjunto de una columna de datos?¡Hermoso! ¡¡¡Gracias!!!
Re: ¿Fórmula para restar el promedio de un subconjunto de una columna de datos?Hola @MarkJSchwab ,
Sí, puedo ver que incluir esto en condicionales puede no ser ideal en muchos casos. Aquí hay una modificación para @brady_brady La solución de 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 y 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 Obtener filas donde():

Como puede ver, todas las filas usan 14 años como subconjunto, pero el subconjunto de sexo está determinado por los valores de fila actuales de sexo. Debe adaptarse fácilmente a diferentes niveles de complejidad.
@Julian
Re: ¿Fórmula para restar el promedio de un subconjunto de una columna de datos?Sólo necesitas ampliar 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 @Julian ¡Gracias de nuevo por la ayuda!
Un último detalle: idealmente me gustaría restar la edad media de las niñas de 14 años a las niñas y la edad media de los niños de 14 años restarla a los niños. (En su ejemplo, está restando la edad de una niña de 14 años tanto de los niños como de las niñas).
(Me doy cuenta de que en este caso específico solo con M/F sería fácil usar un condicional y decir "Si :sex == 'F' entonces usa esta fórmula, si :sex == 'M' luego modifica la fórmula para diga {mean(:height[(:height << get datatable) << get rowswhere( :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 resultarían difíciles de manejar).
¿Alguna forma sencilla de lograr esto?
Re: ¿Fórmula para restar el promedio de un subconjunto de una columna de datos?Hola @MarkJSchwab ,
Parece que <
Aquí hay una solución del asistente jmp. @brady_brady :
:height - Mean( :height[(:height << get datatable) << get rows where( :age == 14 )] )

Vale la pena tomarse un momento para desentrañar esta fórmula porque hay algunos métodos que apuesto que encontrará valiosos para utilizar más adelante.
(:height << get datatable) << get rows where( :age == 14 )
devolverá la matriz de entradas de fila en las que: edad == 14. Es importante destacar que puede modificar la función obtener filas donde() para que coincida con cualquier búsqueda que desee, incluida la segunda solicitud 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 coinciden 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 :height para cada una de esas filas, en este caso, las alturas de las estudiantes 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 a los datos faltantes y funciona para versiones anteriores de jmp, por lo que creo que en conjunto 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 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 de columna general sin seleccionar edad = 14) en lugar del valor correcto que está viendo de 64,166.
Incluso puedo descargar su archivo adjunto y los valores adecuados aparecen en la columna "Centrado con respecto a la media a la edad == 14". Pero si creo una nueva columna en esa tabla con exactamente la misma fórmula, devuelve valores diferentes (mostrando [altura] - [altura promedio general], en lugar de mostrar correctamente [altura] - [altura promedio de 14 años]).
Estoy usando JMP Pro 14.3.0. ¿Alguna idea sobre cómo puedo hacer que mi resultado coincida con el suyo?
Y una pregunta más, en su hoja, si agrega una byVar adicional de :sex (para la fórmula total ":height - (Col Mean( :height, :sex, <Re: ¿Fórmula para restar el promedio de un subconjunto de una columna de datos?
Hola @MarkJSchwab ,
Hay una manera sencilla de hacer esto usando Col Mean() que no es obvia hasta que la ves. Col Mean() toma un argumento de columna de Frecuencia:

Por lo general, esto es para cuando necesitas ponderar usando 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ándonos con respecto a esta media específica desde la altura, podemos incluir 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, MarkJSchwab!
Por supuesto, hay una manera de hacer lo que desees.¡JSL te hará libre!
Escribí un script simple que utiliza principalmente la capacidad de JSL para escribir un script para usted.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 es necesario que lo hagas de esa manera.
Por supuesto, existen formas más sofisticadas de escribir un script como este, especialmente porque todas las cláusulas "dónde" están codificadas y es posible que tenga problemas con este script si su tabla de datos es grande, pero, aún así, JSL será su camino hacia la productividad.¡Hay varios recursos excelentes para aprender JSL!
¡Buena suerte!