Capítulo 4. Análisis de cohortes
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com
En el Capítulo 3 tratamos el análisis de series temporales. Con esas técnicas en la mano, pasaremos ahora a un tipo de análisis relacionado con muchas aplicaciones empresariales y de otro tipo: el análisis de cohortes.
Recuerdo la primera vez que me encontré con un análisis de cohortes. Estaba trabajando en mi primer empleo de analista de datos, en una pequeña startup. Estaba revisando un análisis de compras en el que había trabajado con el director general, y me sugirió que dividiera la base de clientes por cohortes para ver si el comportamiento cambiaba con el tiempo. Supuse que se trataba de algo de la escuela de negocios y probablemente inútil, pero él era el director general, así que le seguí la corriente. Resultó que no era una tontería. Dividir las poblaciones en cohortes y seguirlas a lo largo del tiempo es una forma poderosa de analizar tus datos y evitar diversos sesgos. Las cohortes pueden proporcionar pistas sobre cómo difieren las subpoblaciones entre sí y cómo cambian con el tiempo.
En este capítulo, primero veremos qué son las cohortes y los componentes básicos de ciertos tipos de análisis de cohortes. Tras una introducción al conjunto de datos de legisladores utilizado para los ejemplos, aprenderemos a construir un análisis de retención y a afrontar diversos retos, como la definición de la cohorte y el manejo de datos dispersos. A continuación, trataremos los cálculos de supervivencia, retorno y acumulativos, todos ellos similares al análisis de retención en la forma en que está estructurado el código SQL. Por último, veremos cómo combinar el análisis de cohortes con el análisis transversal para comprender la composición de las poblaciones a lo largo del tiempo.
Cohortes: Un marco de análisis útil
Antes de entrar en el código, definiré qué son las cohortes, consideraré los tipos de preguntas que podemos responder con este tipo de análisis y describiré los componentes de cualquier análisis de cohortes.
Una cohorte es un grupo de individuos que comparten alguna característica de interés, descrita a continuación, en el momento en que empezamos a observarlos. Los miembros de la cohorte suelen ser personas, pero pueden ser cualquier tipo de entidad que queramos estudiar: empresas, productos o fenómenos del mundo físico. Los individuos de una cohorte pueden ser conscientes de su pertenencia, del mismo modo que los niños de una clase de primer grado son conscientes de que forman parte de un grupo de compañeros de primer grado, o los participantes en un ensayo farmacológico son conscientes de que forman parte de un grupo que recibe un tratamiento. Otras veces, las entidades se agrupan en cohortes de forma virtual, como cuando una empresa de software agrupa a todos los clientes adquiridos en un determinado año para estudiar cuánto tiempo siguen siendo clientes. Siempre es importante considerar las implicaciones éticas de agrupar entidades en cohortes sin que sean conscientes de ello, si se les va a aplicar un tratamiento diferente.
El análisis de cohortes es una forma útil de comparar grupos de entidades a lo largo del tiempo. Muchos comportamientos importantes tardan semanas, meses o años en producirse o evolucionar, y el análisis de cohortes es una forma de comprender estos cambios. El análisis de cohortes proporciona un marco para detectar correlaciones entre las características de la cohorte y estas tendencias a largo plazo, lo que puede conducir a hipótesis sobre los factores causales. Por ejemplo, los clientes captados a través de una campaña de marketing pueden tener pautas de compra a largo plazo diferentes de las de los que fueron persuadidos por un amigo para que probaran los productos de una empresa. El análisis de cohortes puede utilizarse para monitorear nuevas cohortes de usuarios o clientes y evaluar cómo se comparan con cohortes anteriores. Este monitoreo puede proporcionar una señal de alerta temprana de que algo ha ido mal (o bien) para los nuevos clientes. El análisis de cohortes también se utiliza para extraer datos históricos. Las pruebas A/B, tratadas en el Capítulo 7, son el patrón oro para determinar la causalidad, pero no podemos retroceder en el tiempo y realizar todas las pruebas para cada pregunta sobre el pasado que nos interese. Por supuesto, debemos ser cautos a la hora de atribuir un significado causal al análisis de cohortes y, en su lugar, utilizar el análisis de cohortes como una forma de comprender a los clientes y generar hipótesis que puedan probarse rigurosamente en el futuro.
Los análisis de cohortes tienen tres componentes: la agrupación de la cohorte, una serie temporal de datos a lo largo de la cual se observa la cohorte, y una métrica agregada que mide una acción realizada por los miembros de la cohorte.
La agrupación por cohortes suele basarse en una fecha de inicio: la fecha de la primera compra o suscripción del cliente, la fecha en que un estudiante empezó la escuela, etc. Sin embargo, las cohortes también pueden formarse en torno a otras características innatas o cambiantes con el tiempo. Las cualidades innatas incluyen el año de nacimiento y el país de origen, o el año en que se fundó una empresa. Las características que pueden cambiar con el tiempo incluyen la ciudad de residencia y el estado civil. Cuando se utilizan éstas, hay que tener cuidado de cohortar sólo en el valor de la fecha de inicio, o de lo contrario las entidades pueden saltar entre grupos de cohortes.
¿Cohorte o segmento?
Estos dos términos se utilizan a menudo de forma similar, o incluso intercambiable, pero merece la pena establecer una distinción entre ellos en aras de la claridad. Una cohorte es un grupo de usuarios (u otras entidades) que tienen una fecha de inicio común y son seguidos a lo largo del tiempo. Un segmento es una agrupación de usuarios que comparten una característica o conjunto de características comunes en un momento dado, independientemente de su fecha de inicio. De forma similar a las cohortes, los segmentos pueden basarse en factores innatos, como la edad, o en características de comportamiento. Un segmento de usuarios que se registra en el mismo mes puede incluirse en una cohorte y seguirse a lo largo del tiempo. O se pueden explorar diferentes agrupaciones de usuarios con el análisis de cohortes para que puedas ver cuáles tienen las características más valiosas. Los análisis que cubriremos en este capítulo, como el de retención, pueden ayudar a poner datos concretos detrás de los segmentos de marketing.
El segundo componente de cualquier análisis de cohortes es la serie temporal. Se trata de una serie de compras, inicios de sesión, interacciones u otras acciones realizadas por los clientes o entidades que se van a cohortar. Es importante que la serie temporal abarque toda la vida de las entidades, o habrá sesgo de supervivencia en las primeras cohortes. El sesgo de supervivencia se produce cuando sólo los clientes que han permanecido están en el conjunto de datos; los clientes que han abandonado se excluyen porque ya no están, de modo que el resto de los clientes parecen de mayor calidad o ajuste en comparación con las cohortes más recientes (véase "Sesgo de supervivencia"). También es importante disponer de una serie temporal lo suficientemente larga para que las entidades completen la acción de interés. Por ejemplo, si los clientes tienden a comprar una vez al mes, se necesita una serie temporal de varios meses. Si, por el contrario, las compras sólo se producen una vez al año, sería preferible una serie temporal de varios años. Inevitablemente, los clientes adquiridos más recientemente no habrán tenido tanto tiempo para completar las acciones como los clientes que fueron adquiridos más en el pasado. Para normalizar, el análisis de cohortes suele medir el número de periodos transcurridos desde una fecha inicial, en lugar de meses naturales. De este modo, las cohortes pueden compararse en el periodo 1, el periodo 2, etc., para ver cómo evolucionan en el tiempo, independientemente del mes en que se produjo realmente la acción. Los intervalos pueden ser de días, semanas, meses o años.
La métrica agregada debe estar relacionada con las acciones que importan para la salud de la organización, como que los clientes sigan utilizando o comprando el producto. Los valores de la métrica se agregan a través de la cohorte, normalmente con sum
, count
, o average
, aunque cualquier agregación relevante funciona. El resultado es una serie temporal que puede utilizarse para comprender los cambios de comportamiento a lo largo del tiempo.
En este capítulo, trataré cuatro tipos de análisis de cohortes: retención, supervivencia, comportamiento de retorno o repetición de compra y comportamiento acumulativo.
- Retención
- La retención se refiere a si el miembro de la cohorte tiene un registro en la serie temporal en una fecha concreta, expresada como un número de periodos desde la fecha de inicio. Esto es útil en cualquier tipo de organización en la que se esperen acciones repetidas, desde jugar a un juego online hasta utilizar un producto o renovar una suscripción, y ayuda a responder preguntas sobre lo pegajoso o atractivo que es un producto y cuántas entidades cabe esperar que aparezcan en fechas futuras.
- Supervivencia
- La Supervivencia se ocupa de cuántas entidades permanecieron en el conjunto de datos durante un determinado periodo de tiempo o más, independientemente del número o la frecuencia de las acciones hasta ese momento. La Supervivencia es útil para responder a preguntas sobre la proporción de la población que cabe esperar que permanezca, ya sea en un sentido positivo al no agitarse o fallecer, o en un sentido negativo al no graduarse o cumplir algún requisito.
- Devolución
- Comportamiento de devolución o repetición de compra se ocupa de si una acción se ha producido más de un umbral mínimo de veces -a menudo simplemente más de una vez- durante una ventana de tiempo fija. Este tipo de análisis es útil en situaciones en las que el comportamiento es intermitente e impredecible, como en el comercio minorista, donde caracteriza la proporción de compradores que repiten en cada cohorte dentro de una ventana temporal fija.
- Acumulativo
- Cálculos acumulativos se refieren al número total o a las cantidades medidas en una o más ventanas temporales fijas, independientemente de cuándo hayan ocurrido durante esa ventana. Los cálculos acumulativos se utilizan a menudo en los cálculos de valor de vida del cliente (LTV o CLTV).
Los cuatro tipos de análisis de cohortes nos permiten comparar subgrupos y comprender cómo difieren a lo largo del tiempo para tomar mejores decisiones sobre productos, marketing y finanzas. Los cálculos de los distintos tipos son similares, así que prepararemos el terreno con la retención, y luego mostraré cómo modificar el código de retención para calcular los otros tipos. Antes de sumergirnos en la construcción de nuestro análisis de cohortes, echemos un vistazo al conjunto de datos que utilizaremos para los ejemplos de este capítulo.
El conjunto de datos de los legisladores
Los ejemplos SQL de este capítulo utilizarán un conjunto de datos de los miembros pasados y presentes del Congreso de los Estados Unidos que se mantiene en un repositorio de GitHub. En US, el Congreso es responsable de redactar las leyes o legislación, por lo que sus miembros también son conocidos como legisladores. Como el conjunto de datos es un archivo JSON, he aplicado algunas transformaciones para producir un modelo de datos más adecuado para el análisis, y he publicado los datos en un formato adecuado para seguir los ejemplos en la carpeta de legisladores de GitHub del libro.
El repositorio de fuentes tiene un excelente diccionario de datos, por lo que no repetiré aquí todos los detalles. Sin embargo, daré algunos detalles que ayudarán a quienes no estén familiarizados con el gobierno de EEUU a seguir los análisis de este capítulo.
El Congreso tiene dos cámaras, el Senado ("sen" en el conjunto de datos) y la Cámara de Representantes ("rep"). Cada estado tiene dos senadores, y son elegidos para mandatos de seis años. Los representantes se asignan a los estados en función de la población; cada representante tiene un distrito al que representa en solitario. Los representantes son elegidos para mandatos de dos años. Los mandatos reales en cualquiera de las cámaras pueden ser más cortos en caso de que el legislador fallezca o sea elegido o nombrado para un cargo superior. Los legisladores acumulan poder e influencia a través de puestos de liderazgo cuanto más tiempo permanecen en el cargo, por lo que es habitual que se presenten a la reelección. Por último, un legislador puede pertenecer a un partido político, o ser un "independiente". En la era moderna, la gran mayoría de los legisladores son demócratas o republicanos, y la rivalidad entre ambos partidos es bien conocida. En ocasiones, los legisladores cambian de partido mientras ocupan sus cargos.
Para los análisis, utilizaremos dos tablas: legislators
y legislators_terms
. La tabla legislators
contiene una lista de todas las personas incluidas en el conjunto de datos, con fecha de nacimiento, sexo y un conjunto de campos de identificación que pueden utilizarse para buscar a la persona en otros conjuntos de datos. La tabla legislators_terms
contiene un registro por cada legislatura de cada legislador, con la fecha de inicio y fin, y otros atributos como la cámara y el partido. El campo id_bioguide
se utiliza como identificador único de un legislador y aparece en cada tabla. La Figura 4-1 muestra una muestra de los datos de legislators
. La Figura 4-2 muestra una muestra de los datos de legislators_terms
.
Ahora que ya sabemos qué es el análisis de cohortes y el conjunto de datos que utilizaremos para los ejemplos, vamos a ver cómo escribir SQL para el análisis de retención. La pregunta clave que SQL nos ayudará a responder es: una vez que los representantes toman posesión de su cargo, ¿cuánto tiempo conservan su empleo?
Retención
Uno de los tipos más comunes de análisis de cohortes es el análisis de retención. Retener es conservar o continuar algo. Hay que practicar muchas habilidades para retenerlas. Las empresas suelen querer que sus clientes sigan comprando sus productos o utilizando sus servicios, ya que retener a los clientes es más rentable que adquirir otros nuevos. Los empresarios quieren conservar a sus empleados, porque contratar sustitutos es caro y lleva mucho tiempo. Los cargos electos buscan la reelección para seguir trabajando en las prioridades de sus electores.
La pregunta principal en el análisis de la retención es si el tamaño inicial de la cohorte -número de abonados o empleados, importe gastado u otra métrica clave- permanecerá constante, decaerá o aumentará con el tiempo. Cuando se produce un aumento o una disminución, la cantidad y la velocidad del cambio también son cuestiones interesantes. En la mayoría de los análisis de retención, el tamaño inicial tenderá a decaer con el tiempo, ya que una cohorte puede perder pero no puede ganar nuevos miembros una vez formada. Los ingresos son una excepción interesante, ya que una cohorte de clientes puede gastar más en los meses siguientes de lo que gastó en el primer mes colectivamente, aunque algunos de ellos se den de baja.
El análisis de retención utiliza el count
de entidades o sum
de dinero o acciones presentes en el conjunto de datos para cada periodo desde la fecha de inicio, y lo normaliza dividiendo este número por el count
o sum
de entidades, dinero o acciones en el primer periodo de tiempo. El resultado se expresa en porcentaje, y la retención en el periodo inicial es siempre del 100%. Con el tiempo, la retención basada en recuentos suele disminuir y nunca puede superar el 100%, mientras que la retención basada en dinero o acciones, aunque suele disminuir, puede aumentar y ser superior al 100% en un periodo de tiempo. El resultado del análisis de la retención suele mostrarse en forma de tabla o gráfico, lo que se denomina curva de retención. Veremos varios ejemplos de curvas de retención más adelante en este capítulo.
Los gráficos de las curvas de retención pueden utilizarse para comparar cohortes. La primera característica a la que hay que prestar atención es la forma de la curva en los primeros periodos, en los que suele haber una caída inicial pronunciada. Para muchas aplicaciones de consumo, es habitual perder la mitad de una cohorte en los primeros meses. Una cohorte con una curva más o menos pronunciada que otras puede indicar cambios en el producto o en la fuente de adquisición de clientes que merecen una investigación más profunda. Una segunda característica que hay que buscar es si la curva se aplana después de cierto número de periodos o si sigue descendiendo rápidamente hasta cero. Una curva que se aplana indica que hay un punto en el tiempo a partir del cual la mayoría de la cohorte que permanece lo hace indefinidamente. Una curva de retención que se inflexiona hacia arriba, a veces llamada curva de la sonrisa, puede producirse si los miembros de la cohorte regresan o se reactivan tras salir del conjunto de datos durante algún periodo. Por último, las curvas de retención que miden los ingresos por suscripción se monitorean para detectar signos de aumento de los ingresos por cliente a lo largo del tiempo, un signo de un negocio de software SaaS saludable.
Esta sección mostrará cómo crear un análisis de retención, añadir agrupaciones de cohortes a partir de la propia serie temporal y de otras tablas, y manejar los datos perdidos y escasos que pueden darse en los datos de series temporales. Con este marco en la mano, en la sección siguiente aprenderás a hacer modificaciones para crear los otros tipos de análisis de cohortes relacionados. Como resultado, esta sección sobre la retención será la más larga del capítulo, ya que construirás código y desarrollarás tu intuición sobre los cálculos.
SQL para una curva de retención básica
Para el análisis de la retención , al igual que para otros análisis de cohortes, necesitamos tres componentes: la definición de la cohorte, una serie temporal de acciones y una métrica agregada que mida algo relevante para la organización o el proceso. En nuestro caso, los miembros de la cohorte serán los legisladores, la serie temporal serán los mandatos en el cargo de cada legislador, y la métrica de interés será el count
de los que siguen en el cargo cada periodo desde la fecha de inicio.
Empezaremos calculando la retención básica, antes de pasar a ejemplos que incluyan diversas agrupaciones de cohortes. El primer paso consiste en hallar la primera fecha de toma de posesión de cada legislador (first_term
). Utilizaremos esta fecha para calcular el número de periodos de cada fecha posterior de la serie temporal. Para ello, toma el min
del term_start
y AGRÚPALO POR cada id_bioguide
, el identificador único de un legislador:
SELECT id_bioguide ,min(term_start) as first_term FROM legislators_terms GROUP BY 1 ; id_bioguide first_term ----------- ---------- A000118 1975-01-14 P000281 1933-03-09 K000039 1933-03-09 ... ...
El siguiente paso es poner este código en una subconsulta y UNIRLO a la serie temporal. Se aplica la función age
para calcular los intervalos entre cada term_start
y el first_term
de cada legislador. Aplicando las funciones date_part
al resultado, con el año, se transforma en el número de periodos anuales. Como las elecciones se celebran cada dos o seis años, utilizaremos años como intervalo de tiempo para calcular los period
s. Podríamos utilizar un intervalo más corto, pero en este conjunto de datos hay poca fluctuación diaria o semanal. El count
de legisladores con registros para ese periodo es el número retenido:
SELECT date_part('year',age(b.term_start,a.first_term)) as period ,count(distinct a.id_bioguide) as cohort_retained FROM ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide GROUP BY 1 ; period cohort_retained ------ --------------- 0.0 12518 1.0 3600 2.0 3619 ... ...
Consejo
En las bases de datos que admiten la función datediff
, las construcciones date_part
y age
pueden sustituirse por esta función más sencilla:
datediff('year',first_term,term_start)
Algunas bases de datos, como Oracle, colocan la date_part
en último lugar:
datediff(first_term,term_start,'year'
Ahora que tenemos los periodos y el número de legisladores retenidos en cada uno, el paso final es calcular el total cohort_size
y rellenarlo en cada fila para poder dividir el cohort_retained
por él. La función de ventana first_value
devuelve el primer registro en la cláusula PARTITION BY, según el orden establecido en ORDER BY, una forma cómoda de obtener el tamaño de la cohorte en cada fila. En este caso, el cohort_size
procede del primer registro de todo el conjunto de datos, por lo que se omite la cláusula PARTITION BY:
first_value(cohort_retained) over (order by period) as cohort_size
Para hallar el porcentaje retenido, divide el valor cohort_retained
por este mismo cálculo:
SELECT period ,first_value(cohort_retained) over (order by period) as cohort_size ,cohort_retained ,cohort_retained / first_value(cohort_retained) over (order by period) as pct_retained FROM ( SELECT date_part('year',age(b.term_start,a.first_term)) as period ,count(distinct a.id_bioguide) as cohort_retained FROM ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide GROUP BY 1 ) aa ; period cohort_size cohort_retained pct_retained ------ ----------- --------------- ------------ 0.0 12518 12518 1.0000 1.0 12518 3600 0.2876 2.0 12518 3619 0.2891 ... ... ... ...
Ahora tenemos un cálculo de retención, y podemos ver que hay una gran caída entre el 100% de los legisladores retenidos en el periodo 0, o en su fecha de inicio, y el porcentaje con otro registro de legislatura que comienza un año después. Si graficamos los resultados, como en la Figura 4-3, veremos cómo la curva se aplana y acaba llegando a cero, ya que incluso los legisladores que llevan más tiempo en el cargo acaban jubilándose o muriendo.
Podemos tomar el resultado de la retención de cohortes y remodelar los datos para mostrarlos en formato de tabla. Pivota y aplana los resultados utilizando una función de agregación con una sentencia CASE; en este ejemplo se utiliza max
, pero otras agregaciones como min
o avg
devolverían el mismo resultado. La retención se calcula para los años 0 a 4, pero pueden añadirse años adicionales siguiendo el mismo patrón:
SELECT cohort_size ,max(case when period = 0 then pct_retained end) as yr0 ,max(case when period = 1 then pct_retained end) as yr1 ,max(case when period = 2 then pct_retained end) as yr2 ,max(case when period = 3 then pct_retained end) as yr3 ,max(case when period = 4 then pct_retained end) as yr4 FROM ( SELECT period ,first_value(cohort_retained) over (order by period) as cohort_size ,cohort_retained / first_value(cohort_retained) over (order by period) as pct_retained FROM ( SELECT date_part('year',age(b.term_start,a.first_term)) as period ,count(*) as cohort_retained FROM ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide GROUP BY 1 ) aa ) aaa GROUP BY 1 ; cohort_size yr0 yr1 yr2 yr3 yr4 ----------- ------ ------ ------ ------ ------ 12518 1.0000 0.2876 0.2891 0.1463 0.2564
La retención parece ser bastante baja, y en el gráfico podemos ver que es irregular en los primeros años. Uno de los motivos es que el mandato de un diputado dura dos años, y el de los senadores seis, pero el conjunto de datos sólo contiene registros del inicio de los nuevos mandatos; por tanto, nos faltan datos de los años en que un legislador seguía en el cargo pero no iniciaba un nuevo mandato. Medir la retención cada año es engañoso en este caso. Una opción es medir la retención sólo en ciclos de dos o seis años, pero también hay otra estrategia que podemos emplear para completar los datos "que faltan". Me referiré a esto a continuación, antes de volver al tema de la formación de grupos de cohortes.
Ajustar las series temporales para aumentar la precisión de la retención
Ya hablamos de las técnicas para limpiar los datos "ausentes" en el Capítulo 2, y volveremos a ellas en esta sección para llegar a una curva de retención más suave y veraz para los legisladores. Cuando se trabaja con datos de series temporales, como en el análisis de cohortes, es importante tener en cuenta no sólo los datos presentes, sino también si esos datos reflejan con exactitud la presencia o ausencia de entidades en cada periodo de tiempo. Esto es especialmente un problema en contextos en los que un acontecimiento capturado en los datos hace que la entidad persista durante algún periodo de tiempo que no está capturado en los datos. Por ejemplo, un cliente que compra una suscripción de software está representado en los datos en el momento de la transacción, pero ese cliente tiene derecho a utilizar el software durante meses o años y no está necesariamente representado en los datos durante ese lapso. Para corregir esto, necesitamos una forma de deducir el lapso de tiempo en el que la entidad sigue presente, ya sea con una fecha de finalización explícita o con el conocimiento de la duración de la suscripción o plazo. Entonces podremos decir que la entidad estaba presente en cualquier fecha comprendida entre esas fechas de inicio y fin.
En el conjunto de datos de los legisladores, tenemos un registro para la fecha de inicio de un mandato, pero nos falta la noción de que esto "da derecho" a un legislador a ejercer durante dos o seis años, según la cámara. Para corregir esto y suavizar la curva, tenemos que rellenar los valores "que faltan" para los años en que los legisladores siguen en el cargo entre los nuevos mandatos. Dado que este conjunto de datos incluye un valor term_end
para cada legislatura, mostraré cómo crear un análisis de retención de cohortes más preciso rellenando las fechas entre los valores inicial y final. Luego mostraré cómo puedes imputar las fechas finales cuando el conjunto de datos no incluya una fecha final.
Calcular la retención utilizando una fecha de inicio y una fecha final definidas en los datos es el planteamiento más exacto. Para los siguientes ejemplos, consideraremos que los legisladores han sido retenidos en un año concreto si seguían en el cargo el último día del año, el 31 de diciembre. Antes de la Vigésima Enmienda a la Constitución de EEUU, los mandatos comenzaban el 4 de marzo, pero después la fecha de inicio se trasladó al 3 de enero, o a un día laborable posterior si el tercero cae en fin de semana. Los legisladores pueden prestar juramento en otros días del año debido a elecciones especiales fuera de ciclo o a nombramientos para cubrir escaños vacantes. En consecuencia, las fechas de term_start
se agrupan en enero, pero se reparten a lo largo del año. Aunque podríamos elegir otro día, el 31 de diciembre es una estrategia para normalizar en torno a estas fechas de inicio variables.
El primer paso es crear un conjunto de datos que contenga un registro por cada 31 de diciembre que cada legislador estuvo en el cargo. Esto se puede conseguir uniendola subconsulta que encontró la tabla first_term
a la tabla legislators_terms
para encontrar las tablas term_start
y term_end
de cada legislatura. Un segundo JOIN a la tabla date_dim
recupera las fechas comprendidas entre las fechas de inicio y fin, restringiendo los valores devueltos a c.month_name = 'December' and c.day_of_month = 31
. period
se calcula como los años comprendidos entre date
de date_dim
y first_term
. Ten en cuenta que aunque hayan transcurrido más de 11 meses entre la jura del cargo en enero y el 31 de diciembre, el primer año sigue apareciendo como 0:
SELECT a.id_bioguide, a.first_term ,b.term_start, b.term_end ,c.date ,date_part('year',age(c.date,a.first_term)) as period FROM ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide LEFT JOIN date_dim c on c.date between b.term_start and b.term_end and c.month_name = 'December' and c.day_of_month = 31 ; id_bioguide first_term term_start term_end date period ----------- ---------- ---------- ---------- ---------- ------ B000944 1993-01-05 1993-01-05 1995-01-03 1993-12-31 0.0 B000944 1993-01-05 1993-01-05 1995-01-03 1994-12-31 1.0 C000127 1993-01-05 1993-01-05 1995-01-03 1993-12-31 0.0 ... ... ... ... ... ...
Consejo
Si no dispones de una dimensión de fecha, puedes crear una subconsulta con las fechas necesarias de un par de formas. Si tu base de datos admite la generate_series
, puedes crear una subconsulta que devuelva las fechas deseadas:
SELECT generate_series::date as date FROM generate_series('1770-12-31','2020-12- 31',interval '1 year')
Puede que quieras guardar esto como una tabla o vista para utilizarlo más adelante. Como alternativa, puedes consultar el conjunto de datos o cualquier otra tabla de la base de datos que tenga un conjunto completo de fechas. En este caso, la tabla tiene todos los años necesarios, pero haremos una fecha de 31 de diciembre para cada año utilizando la función make_date
:
SELECT distinct make_date(date_part('year',term_start)::int,12,31) FROM legislators_terms
Hay varias formas creativas de obtener las series de fechas necesarias. Utiliza el método que esté disponible y sea más sencillo dentro de tus consultas.
Ahora tenemos una fila para cada date
(final de año) para el que queremos calcular la retención. El siguiente paso es calcular el cohort_retained
para cada periodo, lo que se hace con una función count
de id_bioguide
. Se utiliza una función coalesce
de en period
para establecer un valor por defecto de 0 cuando es nulo. Esto se ocupa de los casos en los que el mandato de un legislador comienza y termina en el mismo año, dando crédito por servir en ese año:
SELECT coalesce(date_part('year',age(c.date,a.first_term)),0) as period ,count(distinct a.id_bioguide) as cohort_retained FROM ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide LEFT JOIN date_dim c on c.date between b.term_start and b.term_end and c.month_name = 'December' and c.day_of_month = 31 GROUP BY 1 ; period cohort_retained ------ --------------- 0.0 12518 1.0 12328 2.0 8166 ... ...
El último paso es calcular las cohort_size
y pct_retained
como hicimos anteriormente utilizando las funciones de ventana first_value
:
SELECT period ,first_value(cohort_retained) over (order by period) as cohort_size ,cohort_retained ,cohort_retained * 1.0 / first_value(cohort_retained) over (order by period) as pct_retained FROM ( SELECT coalesce(date_part('year',age(c.date,a.first_term)),0) as period ,count(distinct a.id_bioguide) as cohort_retained FROM ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide LEFT JOIN date_dim c on c.date between b.term_start and b.term_end and c.month_name = 'December' and c.day_of_month = 31 GROUP BY 1 ) aa ; period cohort_size cohort_retained pct_retained ------ ----------- --------------- ------------ 0.0 12518 12518 1.0000 1.0 12518 12328 0.9848 2.0 12518 8166 0.6523 ... ... ... ...
Los resultados, graficados en la Figura 4-4, son ahora mucho más precisos. Casi todos los legisladores siguen en el cargo en el año 1, y la primera gran caída se produce en el año 2, cuando algunos representantes no serán reelegidos.
Si el conjunto de datos no contiene una fecha final, hay un par de opciones para imputar una. Una opción es añadir un intervalo fijo a la fecha de inicio, cuando se conoce la duración de una suscripción o plazo. Esto se puede hacer con la matemática de fechas añadiendo un intervalo constante a la term_start
. Aquí, una sentencia CASE se encarga de la suma para las dos term_type
s:
SELECT a.id_bioguide, a.first_term ,b.term_start ,case when b.term_type = 'rep' then b.term_start + interval '2 years' when b.term_type = 'sen' then b.term_start + interval '6 years' end as term_end FROM ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide ; id_bioguide first_term term_start term_end ----------- ---------- ---------- ---------- B000944 1993-01-05 1993-01-05 1995-01-05 C000127 1993-01-05 1993-01-05 1995-01-05 C000141 1987-01-06 1987-01-06 1989-01-06 ... ... ... ...
Este bloque de código puede introducirse en el código de retención para obtener period
y pct_retained
. El inconveniente de este método es que no recoge los casos en los que un legislador no completó un mandato completo, lo que puede ocurrir en caso de fallecimiento o nombramiento para un cargo superior.
Una segunda opción es utilizar la fecha de inicio posterior, menos un día, como fecha term_end
. Esta puede calcularse con la función de ventana lead
. Esta función es similar a la función lag
que hemos utilizado anteriormente, pero en lugar de devolver un valor de una fila anterior de la partición, devuelve un valor de una fila posterior de la partición, según se determine en la cláusula ORDER BY. El valor por defecto es una fila, que utilizaremos aquí, pero la función tiene un argumento opcional que indica un número diferente de filas. Aquí hallamos la fecha term_start
del término posterior utilizando lead
y luego restamos el intervalo '1 day'
para obtener term_end
:
SELECT a.id_bioguide, a.first_term ,b.term_start ,lead(b.term_start) over (partition by a.id_bioguide order by b.term_start) - interval '1 day' as term_end FROM ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide ; id_bioguide first_term term_start term_end ----------- ---------- ---------- ---------- A000001 1951-01-03 1951-01-03 (null) A000002 1947-01-03 1947-01-03 1949-01-02 A000002 1947-01-03 1949-01-03 1951-01-02 ... ... ... ...
Este bloque de código puede introducirse en el código de retención. Este método tiene un par de inconvenientes. En primer lugar, cuando no hay ningún mandato posterior, la función lead
devuelve nulo, dejando ese mandato sin term_end
. En esos casos podría utilizarse un valor por defecto, como el intervalo por defecto que se muestra en el último ejemplo. El segundo inconveniente es que este método supone que los mandatos son siempre consecutivos, sin tiempo de inactividad. Aunque la mayoría de los legisladores suelen ejercer de forma continuada hasta el final de su carrera parlamentaria, no cabe duda de que hay ejemplos de intervalos entre mandatos de varios años.
Siempre que hagamos ajustes para completar los datos que faltan, debemos tener cuidado con las suposiciones que hacemos. En contextos basados en suscripciones o plazos, las fechas de inicio y fin explícitas suelen ser las más precisas. Cualquiera de los otros dos métodos mostrados -añadir un intervalo fijo o establecer la fecha de finalización en relación con la siguiente fecha de inicio- puede utilizarse cuando no hay fecha de finalización y tenemos una expectativa razonable de que la mayoría de los clientes o usuarios permanecerán durante la duración supuesta.
Ahora que hemos visto cómo calcular una curva de retención básica y corregir las fechas que faltan, podemos empezar a añadir grupos de cohortes. Comparar la retención entre distintos grupos es una de las principales razones para hacer análisis de cohortes. A continuación, hablaré de la formación de grupos a partir de la propia serie temporal y, después, de la formación de grupos de cohortes a partir de datos de otras tablas.
Cohortes derivadas de la propia serie temporal
Ahora que tenemos el código SQL para calcular la retención, podemos empezar a dividir las entidades en cohortes. En esta sección, mostraré cómo derivar agrupaciones de cohortes a partir de la propia serie temporal. Primero hablaré de las cohortes temporales basadas en la primera fecha, y luego explicaré cómo hacer cohortes basadas en otros atributos de la serie temporal.
La forma más habitual de crear las cohortes se basa en la primera o mínima fecha u hora en que aparece la entidad en la serie temporal. Esto significa que sólo se necesita una tabla para el análisis de retención de cohortes: la propia serie temporal. La cohorte por la primera aparición o acción es interesante porque a menudo los grupos que empiezan en momentos diferentes se comportan de forma diferente. En el caso de los servicios al consumidor, los adoptantes tempranos suelen ser más entusiastas y retienen de forma diferente que los adoptantes tardíos, mientras que en el software SaaS, los adoptantes tardíos pueden retener mejor porque el producto está más maduro. Las cohortes temporales pueden agruparse por cualquier granularidad temporal que sea significativa para la organización, aunque son habituales las cohortes semanales, mensuales o anuales. Si no estás seguro de qué agrupación utilizar, prueba a ejecutar el análisis de cohortes con diferentes agrupaciones, sin que el tamaño de las cohortes sea demasiado pequeño, para ver dónde surgen patrones significativos. Afortunadamente, una vez que sabes cómo construir las cohortes y el análisis de retención, sustituir diferentes granularidades temporales es sencillo.
El primer ejemplo utilizará cohortes anuales, y luego demostraré el intercambio en siglos. La cuestión clave que consideraremos es si la época en la que un legislador tomó posesión de su cargo por primera vez tiene alguna correlación con su permanencia en el cargo. Las tendencias políticas y el estado de ánimo del público cambian con el tiempo, pero ¿en qué medida?
Para calcular las cohortes anuales, primero añadimos el año del first_term
calculado anteriormente a la consulta que encuentra los period
y cohort_retained
:
SELECT date_part('year',a.first_term) as first_year ,coalesce(date_part('year',age(c.date,a.first_term)),0) as period ,count(distinct a.id_bioguide) as cohort_retained FROM ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide LEFT JOIN date_dim c on c.date between b.term_start and b.term_end and c.month_name = 'December' and c.day_of_month = 31 GROUP BY 1,2 ; first_year period cohort_retained ---------- ------ --------------- 1789.0 0.0 89 1789.0 2.0 89 1789.0 3.0 57 ... ... ...
A continuación, esta consulta se utiliza como subconsulta, y los valores cohort_size
y pct_retained
se calculan en la consulta externa como antes. En este caso, sin embargo, necesitamos una cláusula PARTITION BY que incluya first_year
para que el first_value
se calcule sólo dentro del conjunto de filas de ese first_year
, en lugar de en todo el conjunto de resultados de la subconsulta:
SELECT first_year, period ,first_value(cohort_retained) over (partition by first_year order by period) as cohort_size ,cohort_retained ,cohort_retained / first_value(cohort_retained) over (partition by first_year order by period) as pct_retained FROM ( SELECT date_part('year',a.first_term) as first_year ,coalesce(date_part('year',age(c.date,a.first_term)),0) as period ,count(distinct a.id_bioguide) as cohort_retained FROM ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide LEFT JOIN date_dim c on c.date between b.term_start and b.term_end and c.month_name = 'December' and c.day_of_month = 31 GROUP BY 1,2 ) aa ; first_year period cohort_size cohort_retained pct_retained ---------- ------ ----------- --------------- ------------ 1789.0 0.0 89 89 1.0000 1789.0 2.0 89 89 1.0000 1789.0 3.0 89 57 0.6404 ... ... ... ... ...
Este conjunto de datos incluye más de doscientos años de inicio, demasiados para graficarlos fácilmente o examinarlos en una tabla. A continuación, examinaremos un intervalo menos granular y cohortaremos a los legisladores por el siglo del first_term
. Este cambio se realiza fácilmente sustituyendo century
por year
en la función date_part
de la subconsulta aa
. Recuerda que los nombres de los siglos están desplazados respecto a los años que representan, de modo que el siglo XVIII duró de 1700 a 1799, el siglo XIX duró de 1800 a 1899, etc. La partición en la función first_value
cambia al campo first_century
:
SELECT first_century, period ,first_value(cohort_retained) over (partition by first_century order by period) as cohort_size ,cohort_retained ,cohort_retained / first_value(cohort_retained) over (partition by first_century order by period) as pct_retained FROM ( SELECT date_part('century',a.first_term) as first_century ,coalesce(date_part('year',age(c.date,a.first_term)),0) as period ,count(distinct a.id_bioguide) as cohort_retained FROM ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide LEFT JOIN date_dim c on c.date between b.term_start and b.term_end and c.month_name = 'December' and c.day_of_month = 31 GROUP BY 1,2 ) aa ORDER BY 1,2 ; first_century period cohort_size cohort_retained pct_retained ------------- ------ ----------- --------------- ------------ 18.0 0.0 368 368 1.0000 18.0 1.0 368 360 0.9783 18.0 2.0 368 242 0.6576 ... ... ... ... ...
Los resultados se representan gráficamente en la Figura 4-5. La retención en los primeros años ha sido mayor para los elegidos por primera vez en el siglo XX o XXI. El siglo XXI aún está en marcha, por lo que muchos de esos legisladores no han tenido la oportunidad de permanecer en el cargo durante cinco o más años, aunque siguen incluidos en el denominador. Podríamos plantearnos eliminar el siglo XXI del análisis, pero lo he dejado aquí para demostrar cómo la curva de retención desciende artificialmente debido a esta circunstancia.
Las cohortes pueden definirse a partir de otros atributos de una serie temporal, además de la primera fecha, con opciones que dependen de los valores de la tabla. La tabla legislators_terms
tiene un campo state
, que indica qué estado representa la persona para ese plazo. Podemos utilizarlo para crear cohortes, y las basaremos en el primer estado para asegurarnos de que cualquier persona que haya representado a varios estados aparezca en los datos sólo una vez.
Advertencia
Al cohortar en función de un atributo que puede cambiar con el tiempo, es importante asegurarse de que a cada entidad se le asigna un solo valor. De lo contrario, la entidad puede estar representada en múltiples cohortes, introduciendo un sesgo en el análisis. Normalmente se utiliza el valor del registro más antiguo del conjunto de datos.
Para encontrar el primer estado de cada legislador, podemos utilizar la función ventana first_value
. En este ejemplo, también convertiremos la función min
en una función ventana para evitar una larga cláusula GROUP BY:
SELECT distinct id_bioguide ,min(term_start) over (partition by id_bioguide) as first_term ,first_value(state) over (partition by id_bioguide order by term_start) as first_state FROM legislators_terms ; id_bioguide first_term first_state ----------- ---------- ----------- C000001 1893-08-07 GA R000584 2009-01-06 ID W000215 1975-01-14 CA ... ... ...
A continuación, podemos introducir este código en nuestro código de retención para hallar la retención en first_state
:
SELECT first_state, period ,first_value(cohort_retained) over (partition by first_state order by period) as cohort_size ,cohort_retained ,cohort_retained / first_value(cohort_retained) over (partition by first_state order by period) as pct_retained FROM ( SELECT a.first_state ,coalesce(date_part('year',age(c.date,a.first_term)),0) as period ,count(distinct a.id_bioguide) as cohort_retained FROM ( SELECT distinct id_bioguide ,min(term_start) over (partition by id_bioguide) as first_term ,first_value(state) over (partition by id_bioguide order by term_start) as first_state FROM legislators_terms ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide LEFT JOIN date_dim c on c.date between b.term_start and b.term_end and c.month_name = 'December' and c.day_of_month = 31 GROUP BY 1,2 ) aa ; first_state period cohort_size cohort_retained pct_retained ----------- ------ ----------- --------------- ------------ AK 0.0 19 19 1.0000 AK 1.0 19 19 1.0000 AK 2.0 19 15 0.7895 ... ... ... ... ...
En la Figura 4-6 se representan gráficamente las curvas de retención de los cinco estados con mayor número total de legisladores. Los elegidos en Illinois y Massachusetts tienen la retención más alta, mientras que los neoyorquinos tienen la retención más baja. Determinar las razones sería una rama interesante de este análisis.
Definir cohortes a partir de las series temporales es relativamente sencillo utilizando una fecha min
para cada entidad y convirtiendo luego esa fecha en un mes, año o siglo, según convenga para el análisis. Cambiar entre mes y año u otros niveles de granularidad también es sencillo, lo que permite probar múltiples opciones para encontrar una agrupación que sea significativa para la organización. Se pueden utilizar otros atributos para la cohorte con la función de ventana first_value
. A continuación, pasaremos a los casos en los que el atributo de cohorte procede de una tabla distinta a la de la serie temporal.
Definir la cohorte a partir de una tabla separada
A menudo, las características que definen una cohorte existen en una tabla independiente de la que contiene las series temporales. Por ejemplo, una base de datos puede tener una tabla de clientes con información como el origen de la adquisición o la fecha de registro, por la que se puede cohortar a los clientes. Añadir atributos de otras tablas, o incluso subconsultas, es relativamente sencillo y puede hacerse en el análisis de retención y otros análisis relacionados que se tratan más adelante en el capítulo.
Para este ejemplo, consideraremos si el sexo del legislador tiene algún impacto en su retención. La tabla legislators
tiene un campo gender
, donde F significa mujer y M significa hombre, que podemos utilizar para cohortar a los legisladores. Para ello, uniremos la tabla legislators
con el alias d
para añadir gender
al cálculo de cohort_retained
, en lugar de año o siglo:
SELECT d.gender ,coalesce(date_part('year',age(c.date,a.first_term)),0) as period ,count(distinct a.id_bioguide) as cohort_retained FROM ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide LEFT JOIN date_dim c on c.date between b.term_start and b.term_end and c.month_name = 'December' and c.day_of_month = 31 JOIN legislators d on a.id_bioguide = d.id_bioguide GROUP BY 1,2 ; gender period cohort_retained ------ ------ --------------- F 0.0 366 M 0.0 12152 F 1.0 349 M 1.0 11979 ... ... ...
Inmediatamente queda claro que muchos más hombres que mujeres han cumplido legislaturas. Ahora podemos calcular la percent_retained
para poder comparar la retención de estos grupos:
SELECT gender, period ,first_value(cohort_retained) over (partition by gender order by period) as cohort_size ,cohort_retained ,cohort_retained/ first_value(cohort_retained) over (partition by gender order by period) as pct_retained FROM ( SELECT d.gender ,coalesce(date_part('year',age(c.date,a.first_term)),0) as period ,count(distinct a.id_bioguide) as cohort_retained FROM ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide LEFT JOIN date_dim c on c.date between b.term_start and b.term_end and c.month_name = 'December' and c.day_of_month = 31 JOIN legislators d on a.id_bioguide = d.id_bioguide GROUP BY 1,2 ) aa ; gender period cohort_size cohort_retained pct_retained ------ ------ ----------- --------------- ------------ F 0.0 366 366 1.0000 M 0.0 12152 12152 1.0000 F 1.0 366 349 0.9536 M 1.0 12152 11979 0.9858 ... ... ... ... ...
Podemos ver en los resultados graficados en la Figura 4-7 que la retención es mayor para las legisladoras que para sus homólogos masculinos en los periodos 2 a 29. La primera legisladora no tomó posesión de su cargo hasta 1917, cuando Jeannette Rankin se incorporó a la Cámara como representante republicana por Montana. Como hemos visto antes, la retención ha aumentado en los siglos más recientes.
Para hacer una comparación más justa, podríamos restringir los legisladores incluidos en el análisis a sólo aquellos cuyo first_term
comenzó desde que hay mujeres en el Congreso. Podemos hacerlo añadiendo un filtro WHERE a la subconsulta aa
. Aquí los resultados también se restringen a los que empezaron antes de 2000, para garantizar que las cohortes han tenido al menos 20 años posibles para permanecer en el cargo:
SELECT gender, period ,first_value(cohort_retained) over (partition by gender order by period) as cohort_size ,cohort_retained ,cohort_retained / first_value(cohort_retained) over (partition by gender order by period) as pct_retained FROM ( SELECT d.gender ,coalesce(date_part('year',age(c.date,a.first_term)),0) as period ,count(distinct a.id_bioguide) as cohort_retained FROM ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide LEFT JOIN date_dim c on c.date between b.term_start and b.term_end and c.month_name = 'December' and c.day_of_month = 31 JOIN legislators d on a.id_bioguide = d.id_bioguide WHERE a.first_term between '1917-01-01' and '1999-12-31' GROUP BY 1,2 ) aa ; gender period cohort_size cohort_retained pct_retained ------ ------ ----------- --------------- ------------ F 0.0 200 200 1.0000 M 0.0 3833 3833 1.0000 F 1.0 200 187 0.9350 M 1.0 3833 3769 0.9833 ... ... ... ... ...
Los legisladores varones siguen superando en número a las legisladoras, pero por un margen menor. La retención de las cohortes se representa gráficamente en la Figura 4-8. Con las cohortes revisadas, los legisladores varones tienen mayor retención hasta el año 7, pero a partir del año 12, las legisladoras tienen mayor retención. La diferencia entre los dos análisis de cohortes basados en el género subraya la importancia de establecer cohortes adecuadas y de asegurarse de que disponen de cantidades de tiempo comparables para estar presentes o completar otras acciones de interés. Para mejorar aún más este análisis, podríamos establecer cohortes tanto por año o década de inicio como por género, a fin de controlar los cambios adicionales en la retención a lo largo del siglo XX y en el siglo XXI.
Las cohortes pueden definirse de múltiples formas, a partir de las series temporales y de otras tablas. Con el marco que hemos desarrollado, se pueden intercambiar subconsultas, vistas u otras tablas derivadas, abriendo toda una gama de cálculos para que sean la base de una cohorte. Pueden utilizarse múltiples criterios, como el año de inicio y el sexo. Una precaución al dividir poblaciones en cohortes basadas en criterios múltiples es que esto puede dar lugar a cohortes dispersas, en las que algunos de los grupos definidos son demasiado pequeños y no están representados en el conjunto de datos para todos los periodos de tiempo. En la siguiente sección se analizan métodos para superar este reto.
Tratar con cohortes dispersas
En el conjunto de datos ideal, cada cohorte tiene alguna acción o registro en la serie temporal para cada periodo de interés. Ya hemos visto cómo pueden producirse fechas "perdidas" debido a suscripciones o plazos que duran varios periodos, y vimos cómo corregirlas utilizando una dimensión de fecha para inferir fechas intermedias. Otro problema puede surgir cuando, debido a criterios de agrupación, la cohorte resulta demasiado pequeña y, como resultado, sólo está representada esporádicamente en los datos. Una cohorte puede desaparecer del conjunto de resultados, cuando preferiríamos que apareciera con un valor de retención cero. Este problema se denomina cohortes dispersas, y puede solucionarse con un uso cuidadoso de las JOIN IZQUIERDAS.
Para demostrarlo, intentemos agrupar a las legisladoras por el primer estado al que representaron para ver si hay diferencias en la permanencia. Ya hemos visto que ha habido relativamente pocas legisladoras. Cohortarlas aún más por estado es muy probable que cree algunas cohortes dispersas en las que haya muy pocos miembros. Antes de hacer los ajustes de código, añadamos first_state
(calculado en la sección sobre derivar cohortes de las series temporales) a nuestro ejemplo anterior de género y observemos los resultados:
SELECT first_state, gender, period ,first_value(cohort_retained) over (partition by first_state, gender order by period) as cohort_size ,cohort_retained ,cohort_retained / first_value(cohort_retained) over (partition by first_state, gender order by period) as pct_retained FROM ( SELECT a.first_state, d.gender ,coalesce(date_part('year',age(c.date,a.first_term)),0) as period ,count(distinct a.id_bioguide) as cohort_retained FROM ( SELECT distinct id_bioguide ,min(term_start) over (partition by id_bioguide) as first_term ,first_value(state) over (partition by id_bioguide order by term_start) as first_state FROM legislators_terms ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide LEFT JOIN date_dim c on c.date between b.term_start and b.term_end and c.month_name = 'December' and c.day_of_month = 31 JOIN legislators d on a.id_bioguide = d.id_bioguide WHERE a.first_term between '1917-01-01' and '1999-12-31' GROUP BY 1,2,3 ) aa ; first_state gender period cohort_size cohort_retained pct_retained ----------- ------ ------ ----------- --------------- ------------ AZ F 0.0 2 2 1.0000 AZ M 0.0 26 26 1.0000 AZ F 1.0 2 2 1.0000 ... ... ... ... ... ...
Si se grafican los resultados de los 20 primeros periodos, como en la Figura 4-9, se observa la escasez de cohortes. Alaska no tuvo ninguna legisladora, mientras que la curva de retención femenina de Arizona desaparece después del 3er año. Sólo California, un estado grande con muchos legisladores, tiene curvas de retención completas para ambos sexos. Este patrón se repite para otros estados pequeños y grandes.
Veamos ahora cómo garantizar un registro para cada periodo, de forma que la consulta devuelva valores cero para la retención en lugar de nulos. El primer paso es consultar todas las combinaciones de period
s y atributos de cohorte, en este caso first_state
y gender
, con el cohort_size
inicial para cada combinación. Esto puede hacerse uniendola subconsulta aa
, que calcula la cohorte, con una subconsulta generate_series
que devuelve todos los enteros de 0 a 20, con los criterios on 1 = 1
. Esta es una forma práctica de forzar una JOIN cartesiana cuando las dos subconsultas no tienen ningún campo en común:
SELECT aa.gender, aa.first_state, cc.period, aa.cohort_size
FROM
(
SELECT b.gender, a.first_state
,count(distinct a.id_bioguide) as cohort_size
FROM
(
SELECT distinct id_bioguide
,min(term_start) over (partition by id_bioguide) as first_term
,first_value(state) over (partition by id_bioguide
order by term_start) as first_state
FROM legislators_terms
) a
JOIN legislators b on a.id_bioguide = b.id_bioguide
WHERE a.first_term between '1917-01-01' and '1999-12-31'
GROUP BY 1,2
) aa
JOIN
(
SELECT generate_series as period
FROM generate_series(0,20,1)
) cc on 1 = 1
;
gender state period cohort
------ ----- ------ ------
F AL 0 3
F AL 1 3
F AL 2 3
... ... ... ...
El siguiente paso es volver a UNIR esto a los periodos reales en el cargo, con una UNIÓN IZQUIERDA para garantizar que todos los periodos de tiempo permanecen en el resultado final:
SELECT aaa.gender, aaa.first_state, aaa.period, aaa.cohort_size ,coalesce(ddd.cohort_retained,0) as cohort_retained ,coalesce(ddd.cohort_retained,0) / aaa.cohort_size as pct_retained FROM ( SELECT aa.gender, aa.first_state, cc.period, aa.cohort_size FROM ( SELECT b.gender, a.first_state ,count(distinct a.id_bioguide) as cohort_size FROM ( SELECT distinct id_bioguide ,min(term_start) over (partition by id_bioguide) as first_term ,first_value(state) over (partition by id_bioguide order by term_start) as first_state FROM legislators_terms ) a JOIN legislators b on a.id_bioguide = b.id_bioguide WHERE a.first_term between '1917-01-01' and '1999-12-31' GROUP BY 1,2 ) aa JOIN ( SELECT generate_series as period FROM generate_series(0,20,1) ) cc on 1 = 1 ) aaa LEFT JOIN ( SELECT d.first_state, g.gender ,coalesce(date_part('year',age(f.date,d.first_term)),0) as period ,count(distinct d.id_bioguide) as cohort_retained FROM ( SELECT distinct id_bioguide ,min(term_start) over (partition by id_bioguide) as first_term ,first_value(state) over (partition by id_bioguide order by term_start) as first_state FROM legislators_terms ) d JOIN legislators_terms e on d.id_bioguide = e.id_bioguide LEFT JOIN date_dim f on f.date between e.term_start and e.term_end and f.month_name = 'December' and f.day_of_month = 31 JOIN legislators g on d.id_bioguide = g.id_bioguide WHERE d.first_term between '1917-01-01' and '1999-12-31' GROUP BY 1,2,3 ) ddd on aaa.gender = ddd.gender and aaa.first_state = ddd.first_state and aaa.period = ddd.period ; gender first_state period cohort_size cohort_retained pct_retained ------ ----------- ------ ----------- --------------- ------------ F AL 0 3 3 1.0000 F AL 1 3 1 0.3333 F AL 2 3 0 0.0000 ... ... ... ... ... ...
A continuación, podemos hacer pivotar los resultados y confirmar que existe un valor para cada cohorte en cada periodo:
gender first_state yr0 yr2 yr4 yr6 yr8 yr10 ------ ----------- ----- ------ ------ ------ ------ ------ F AL 1.000 0.0000 0.0000 0.0000 0.0000 0.0000 F AR 1.000 0.8000 0.2000 0.4000 0.4000 0.4000 F CA 1.000 0.9200 0.8000 0.6400 0.6800 0.6800 ... ... ... ... ... ... ... ...
Observa que en este punto, el código SQL se ha hecho bastante largo. Una de las partes más difíciles de escribir SQL para el análisis de retención de cohortes es mantener toda la lógica recta y el código organizado, un tema que trataré con más detalle en el Capítulo 8. Cuando construyo el código de retención, me resulta útil ir paso a paso, comprobando los resultados por el camino. También compruebo al azar cohortes individuales para validar que el resultado final es exacto.
Las cohortes pueden definirse de muchas formas. Hasta ahora, hemos normalizado todas nuestras cohortes a la primera fecha en que aparecen en los datos de la serie temporal. Sin embargo, ésta no es la única opción, y se pueden realizar análisis interesantes a partir de la mitad de la vida de una entidad. Antes de concluir nuestro trabajo sobre el análisis de la retención, echemos un vistazo a esta forma adicional de definir las cohortes.
Definir cohortes a partir de fechas distintas de la primera cita
Normalmente las cohortes temporales se definen a partir de la primera aparición de la entidad en la serie temporal o a partir de alguna otra fecha más temprana, como la fecha de registro. Sin embargo, crear cohortes a partir de una fecha diferente puede ser útil y revelador. Por ejemplo, podríamos querer analizar la retención de todos los clientes que utilizan un servicio a partir de una fecha determinada. Este tipo de análisis puede utilizarse para comprender si los cambios de producto o de marketing han tenido un impacto a largo plazo en los clientes existentes.
Si utilizamos una fecha distinta de la primera, debemos tener cuidado de definir con precisión los criterios de inclusión en cada cohorte. Una opción es elegir las entidades presentes en una fecha concreta del calendario. Esto es relativamente sencillo de poner en código SQL, pero puede ser problemático si una gran parte de la población de usuarios habituales no se presenta todos los días, haciendo que la retención varíe en función del día exacto elegido. Una opción para corregir esto es calcular la retención para varias fechas de inicio y luego hacer una media de los resultados.
Otra opción es utilizar una ventana de tiempo, como una semana o un mes. Cualquier entidad que aparezca en el conjunto de datos durante esa ventana se incluye en la cohorte. Aunque este enfoque suele ser más representativo de la empresa o el proceso, la contrapartida es que el código SQL se volverá más complejo, y el tiempo de consulta puede ser más lento debido a los cálculos más intensos de la base de datos. Encontrar el equilibrio adecuado entre el rendimiento de la consulta y la precisión de los resultados es una especie de arte.
Veamos cómo calcular ese análisis intermedio con el conjunto de datos de los legisladores, considerando la retención de los legisladores que estaban en el cargo en el año 2000. Nos basaremos en term_type
, que tiene los valores "sen" para los senadores y "rep" para los representantes. La definición incluirá a cualquier legislador en el cargo en cualquier momento del año 2000: los que empezaron antes de 2000 y cuyos mandatos terminaron durante o después de 2000 cumplen los requisitos, al igual que los que empezaron un mandato en 2000. Podemos codificar cualquier fecha del año 2000 como first_term
, ya que después comprobaremos si estuvieron en el cargo en algún momento del año 2000. El min_start
de los mandatos que caen en esta ventana también se calcula para utilizarlo en un paso posterior:
SELECT distinct id_bioguide, term_type, date('2000-01-01') as first_term
,min(term_start) as min_start
FROM legislators_terms
WHERE term_start <= '2000-12-31' and term_end >= '2000-01-01'
GROUP BY 1,2,3
;
id_bioguide term_type first_term min_start
----------- --------- ---------- ---------
C000858 sen 2000-01-01 1997-01-07
G000333 sen 2000-01-01 1995-01-04
M000350 rep 2000-01-01 1999-01-06
... ... ... ...
A continuación, podemos introducir esto en nuestro código de retención, con dos ajustes. En primer lugar, se añade un criterio JOIN adicional entre la subconsulta a
y la tabla legislators_terms
para devolver sólo los términos que empezaron en la fecha min_start
o después. En segundo lugar, se añade un filtro adicional a la date_dim
para que sólo devuelva date
s en 2000 o posteriores:
SELECT term_type, period ,first_value(cohort_retained) over (partition by term_type order by period) as cohort_size ,cohort_retained ,cohort_retained / first_value(cohort_retained) over (partition by term_type order by period) as pct_retained FROM ( SELECT a.term_type ,coalesce(date_part('year',age(c.date,a.first_term)),0) as period ,count(distinct a.id_bioguide) as cohort_retained FROM ( SELECT distinct id_bioguide, term_type ,date('2000-01-01') as first_term ,min(term_start) as min_start FROM legislators_terms WHERE term_start <= '2000-12-31' and term_end >= '2000-01-01' GROUP BY 1,2,3 ) a JOIN legislators_terms b on a.id_bioguide = b.id_bioguide and b.term_start >= a.min_start LEFT JOIN date_dim c on c.date between b.term_start and b.term_end and c.month_name = 'December' and c.day_of_month = 31 and c.year >= 2000 GROUP BY 1,2 ) aa ; term_type period cohort_size cohort_retained pct_retained --------- ------ ----------- --------------- ------------ rep 0.0 440 440 1.0000 sen 0.0 101 101 1.0000 rep 1.0 440 392 0.8909 sen 1.0 101 89 0.8812 ... ... ... ... ...
La Figura 4-10 muestra que, a pesar de los mandatos más largos de los senadores, la retención entre las dos cohortes fue similar, y de hecho fue peor para los senadores después de 10 años. Un análisis más detallado en el que se compararan los distintos años en que fueron elegidos por primera vez, u otros atributos de la cohorte, podría arrojar algunas conclusiones interesantes.
Un caso de uso común para la cohorte sobre un valor distinto de un valor inicial es cuando se intenta analizar la retención después de que una entidad haya alcanzado un umbral, como un cierto número de compras o una cierta cantidad gastada. Como con cualquier cohorte, es importante tener cuidado al definir qué califica a una entidad para estar en una cohorte y qué fecha se utilizará como fecha de inicio.
La cohorte de retención es una forma poderosa de comprender el comportamiento de las entidades en un conjunto de datos de series temporales. Hemos visto cómo calcular la retención con SQL y cómo hacer cohortes basadas en la propia serie temporal o en otras tablas, y a partir de puntos intermedios de la vida de las entidades. También hemos visto cómo utilizar funciones y JOINspara ajustar fechas dentro de series temporales y compensar cohortes dispersas. Hay varios tipos de análisis relacionados con la retención de cohortes: análisis, supervivencia, retorno y cálculos acumulativos, todos ellos basados en el código SQL que hemos desarrollado para la retención. Pasemos a ellos a continuación.
Análisis transversal, a través de una lente de cohorte
Hasta ahora, en este capítulo, hemos examinado el análisis de cohortes. Hemos seguido el comportamiento de las cohortes a lo largo del tiempo con análisis de retención, supervivencia, retorno y comportamiento acumulativo. Sin embargo, uno de los retos de estos análisis es que, aunque facilitan la detección de cambios dentro de las cohortes, puede resultar difícil detectar cambios en la composición general de una base de clientes o usuarios.
También pueden producirsecambios en la mezcla, que son cambios en la composición de la base de clientes o usuarios a lo largo del tiempo, que hacen que las cohortes posteriores sean diferentes de las anteriores. Los cambios de mezcla pueden deberse a la expansión internacional, al cambio entre estrategias de adquisición orgánica y de pago, o al paso de un público entusiasta de nicho a otro más amplio de mercado de masas. Crear cohortes adicionales, o segmentos, a lo largo de cualquiera de estas líneas sospechosas puede ayudar a diagnosticar si se está produciendo un cambio de mezcla.
El análisis de cohortes puede contrastarse con el análisis transversal, que compara individuos o grupos en un único momento. Los estudios transversales pueden correlacionar los años de educación con los ingresos actuales, por ejemplo. En el lado positivo, la recopilación de conjuntos de datos para el análisis transversal suele ser más fácil, ya que no se necesitan series temporales. El análisis transversal puede ser esclarecedor y generar hipótesis para investigaciones posteriores. En el lado negativo, suele existir una forma de sesgo de selección denominada sesgo de supervivencia, que puede llevar a conclusiones falsas.
El análisis de cohortes es una forma de superar el sesgo de supervivencia incluyendo en el análisis a todos los miembros de una cohorte inicial. Podemos tomar una serie de secciones transversales de un análisis de cohortes para comprender cómo puede haber cambiado la mezcla de entidades a lo largo del tiempo. En una fecha determinada, hay usuarios de diversas cohortes. Podemos utilizar el análisis transversal para examinarlos, como capas de sedimento, y revelar nuevas perspectivas. En el siguiente ejemplo, crearemos una serie temporal de la proporción de legisladores de cada cohorte para cada año del conjunto de datos.
El primer paso es hallar el número de legisladores en funciones cada año uniendola tabla legislators
a la date_dim
, DONDE date
de date_dim
está entre las fechas de inicio y fin de cada legislatura. Aquí utilizamos el 31 de diciembre de cada año para encontrar los legisladores en funciones al final de cada año:
SELECT b.date, count(distinct a.id_bioguide) as legislators FROM legislators_terms a JOIN date_dim b on b.date between a.term_start and a.term_end and b.month_name = 'December' and b.day_of_month = 31 and b.year <= 2019 GROUP BY 1 ; date legislators ---------- ----------- 1789-12-31 89 1790-12-31 95 1791-12-31 99 ... ...
A continuación, añadimos los criterios de cohorte del siglo mediante un JOINa una subconsulta con el first_term
calculado:
SELECT b.date ,date_part('century',first_term) as century ,count(distinct a.id_bioguide) as legislators FROM legislators_terms a JOIN date_dim b on b.date between a.term_start and a.term_end and b.month_name = 'December' and b.day_of_month = 31 and b.year <= 2019 JOIN ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) c on a.id_bioguide = c.id_bioguide GROUP BY 1,2 ; date century legislators ---------- ------- ----------- 1789-12-31 18 89 1790-12-31 18 95 1791-12-31 18 99 ... ... ...
Por último, calculamos el porcentaje del total de legislators
en cada año que representa la cohorte del siglo. Esto puede hacerse de un par de maneras, dependiendo de la forma de salida deseada. La primera forma es mantener una fila para cada combinación de date
y century
y utilizar una función de ventana sum
en el denominador del cálculo del porcentaje:
SELECT date ,century ,legislators ,sum(legislators) over (partition by date) as cohort ,legislators / sum(legislators) over (partition by date) as pct_century FROM ( SELECT b.date ,date_part('century',first_term) as century ,count(distinct a.id_bioguide) as legislators FROM legislators_terms a JOIN date_dim b on b.date between a.term_start and a.term_end and b.month_name = 'December' and b.day_of_month = 31 and b.year <= 2019 JOIN ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) c on a.id_bioguide = c.id_bioguide GROUP BY 1,2 ) a ; date century legislators cohort pct_century ---------- ------- ----------- ------ ----------- 2018-12-31 20 122 539 0.2263 2018-12-31 21 417 539 0.7737 2019-12-31 20 97 537 0.1806 2019-12-31 21 440 537 0.8194 ... ... ... ... ...
El segundo enfoque da como resultado una fila por año, con una columna para cada siglo, un formato de tabla que puede ser más fácil de explorar en busca de tendencias:
SELECT date ,coalesce(sum(case when century = 18 then legislators end) / sum(legislators),0) as pct_18 ,coalesce(sum(case when century = 19 then legislators end) / sum(legislators),0) as pct_19 ,coalesce(sum(case when century = 20 then legislators end) / sum(legislators),0) as pct_20 ,coalesce(sum(case when century = 21 then legislators end) / sum(legislators),0) as pct_21 FROM ( SELECT b.date ,date_part('century',first_term) as century ,count(distinct a.id_bioguide) as legislators FROM legislators_terms a JOIN date_dim b on b.date between a.term_start and a.term_end and b.month_name = 'December' and b.day_of_month = 31 and b.year <= 2019 JOIN ( SELECT id_bioguide, min(term_start) as first_term FROM legislators_terms GROUP BY 1 ) c on a.id_bioguide = c.id_bioguide GROUP BY 1,2 ) aa GROUP BY 1 ; date pct_18 pct_19 pct_20 pct_21 ---------- ------ ------ ------ ------ 2017-12-31 0 0 0.2305 0.7695 2018-12-31 0 0 0.2263 0.7737 2019-12-31 0 0 0.1806 0.8193 ... ... ... ... ...
Podemos representar gráficamente el resultado, como en la Figura 4-13, para ver cómo las nuevas cohortes de legisladores superan gradualmente a las antiguas, hasta que ellas mismas son sustituidas por nuevas cohortes.
En lugar de cohortar en first_term
, podemos cohortar en función de la antigüedad. Encontrar la proporción de clientes que son relativamente nuevos, que tienen una antigüedad media o que son clientes de larga duración en distintos momentos puede ser revelador. Veamos cómo ha cambiado la permanencia de los legisladores en el Congreso a lo largo del tiempo.
El primer paso es calcular, para cada año, el número acumulado de años en el cargo de cada legislador. Como puede haber lagunas entre legislaturas cuando los legisladores son expulsados o dejan el cargo por otras razones, primero encontraremos cada año en el que el legislador estaba en el cargo al final del año, en la subconsulta. Luego utilizaremos una función de ventana count
, con la ventana cubriendo las filas unbounded preceding
, o todas las filas anteriores de ese legislador, y current row
:
SELECT id_bioguide, date ,count(date) over (partition by id_bioguide order by date rows between unbounded preceding and current row ) as cume_years
FROM ( SELECT distinct a.id_bioguide, b.date FROM legislators_terms a JOIN date_dim b on b.date between a.term_start and a.term_end and b.month_name = 'December' and b.day_of_month = 31 and b.year <= 2019 ) aa ; id_bioguide date cume_years ----------- ---------- ---------- A000001 1951-12-31 1 A000001 1952-12-31 2 A000002 1947-12-31 1 A000002 1948-12-31 2 A000002 1949-12-31 3 ... ... ...
A continuación, count
el número de legisladores de cada combinación de date
y cume_years
para crear una distribución:
SELECT date, cume_years ,count(distinct id_bioguide) as legislators FROM ( SELECT id_bioguide, date ,count(date) over (partition by id_bioguide order by date rows between unbounded preceding and current row ) as cume_years FROM ( SELECT distinct a.id_bioguide, b.date FROM legislators_terms a JOIN date_dim b on b.date between a.term_start and a.term_end and b.month_name = 'December' and b.day_of_month = 31 and b.year <= 2019 GROUP BY 1,2 ) aa ) aaa GROUP BY 1,2 ; date cume_years legislators ----------- ---------- ---------- 1789-12-31 1 89 1790-12-31 1 6 1790-12-31 2 89 1791-12-31 1 37 ... ... ...
Antes de calcular el porcentaje de cada titularidad por año y ajustar el formato de presentación, podríamos considerar la posibilidad de agrupar las titularidades. Un rápido perfil de nuestros resultados hasta ahora revela que en algunos años están representadas casi 40 tenencias diferentes. Es probable que esto resulte difícil de visualizar e interpretar:
SELECT date, count(*) as tenures FROM ( SELECT date, cume_years ,count(distinct id_bioguide) as legislators FROM ( SELECT id_bioguide, date ,count(date) over (partition by id_bioguide order by date rows between unbounded preceding and current row ) as cume_years FROM ( SELECT distinct a.id_bioguide, b.date FROM legislators_terms a JOIN date_dim b on b.date between a.term_start and a.term_end and b.month_name = 'December' and b.day_of_month = 31 and b.year <= 2019 GROUP BY 1,2 ) aa ) aaa GROUP BY 1,2 ) aaaa GROUP BY 1 ; date tenures ----------- ------- 1998-12-31 39 1994-12-31 39 1996-12-31 38 ... ...
En consecuencia, es posible que queramos agrupar los valores. No hay una única forma correcta de agrupar tenencias. Si existen definiciones organizativas de grupos de tenencias, utilízalas. De lo contrario, suelo intentar dividirlos en tres o cinco grupos de aproximadamente el mismo tamaño. Aquí agruparemos las permanencias en cuatro cohortes, donde cume_years
es igual o inferior a 4 años, entre 5 y 10 años, entre 11 y 20 años, e igual o superior a 21 años:
SELECT date, tenure ,legislators / sum(legislators) over (partition by date) as pct_legislators FROM ( SELECT date ,case when cume_years <= 4 then '1 to 4' when cume_years <= 10 then '5 to 10' when cume_years <= 20 then '11 to 20' else '21+' end as tenure ,count(distinct id_bioguide) as legislators FROM ( SELECT id_bioguide, date ,count(date) over (partition by id_bioguide order by date rows between unbounded preceding and current row ) as cume_years FROM ( SELECT distinct a.id_bioguide, b.date FROM legislators_terms a JOIN date_dim b on b.date between a.term_start and a.term_end and b.month_name = 'December' and b.day_of_month = 31 and b.year <= 2019 GROUP BY 1,2 ) a ) aa GROUP BY 1,2 ) aaa ; date tenure pct_legislators ---------- ------- --------------- 2019-12-31 1 to 4 0.2998 2019-12-31 5 to 10 0.3203 2019-12-31 11 to 20 0.2011 2019-12-31 21+ 0.1788 ... ... ...
El gráfico de resultados de la Figura 4-14 muestra que en los primeros años del país, la mayoría de los legisladores tenían muy pocos años de mandato. En años más recientes, la proporción de legisladores con 21 o más años en el cargo ha ido en aumento. También hay interesantes aumentos periódicos de legisladores con una permanencia de 1 a 4 años, que pueden reflejar cambios en las tendencias políticas.
Una sección transversal de una población en un momento dado está formada por miembros de múltiples cohortes. Crear una serie temporal de estas secciones transversales es otra forma interesante de analizar las tendencias. Combinando esto con las percepciones de la retención se puede obtener una imagen más sólida de las tendencias en cualquier organización.
Conclusión
El análisis de cohortes es una forma útil de investigar cómo cambian los grupos a lo largo del tiempo, ya sea desde la perspectiva de la retención, la repetición de conductas o la acumulación de acciones. El análisis de cohortes es retrospectivo, y mira hacia atrás en las poblaciones utilizando atributos intrínsecos o derivados del comportamiento. Mediante este tipo de análisis pueden encontrarse correlaciones interesantes y, con suerte, útiles. Sin embargo, como dice el refrán, correlación no implica causalidad. Para determinar la causalidad real, los experimentos aleatorios son la regla de oro. El Capítulo 7 profundizará en el análisis de experimentos.
Sin embargo, antes de pasar a la experimentación, tenemos que tratar otros tipos de análisis. A continuación trataremos el análisis de texto: los componentes del análisis de texto suelen aparecer en otros análisis, y es una faceta interesante del análisis en sí misma.
Get SQL para análisis de datos now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.