No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Muestreo estratificado en Python

6/22
Recursos

Aportes 16

Preguntas 4

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

Muestreo Estratificado en Python

Yo lo entend铆 de esta forma:

  1. Separa los datos por categor铆as (valores estratificados).
  2. Define las categor铆as que quieres en t煤 muestro y su proporci贸n.
  3. Toma tantos datos como necesites de cada categor铆a para llegar a la proporci贸n deseada.
  4. Junta esas muestras de cada categor铆a para tu muestreo final.

Explicaci贸n del ejemplo

Se crean dichas categor铆as a partir de la delegaci贸n y el tipo, esta informaci贸n se almacena en la columna estratificado:

econdata['estratificado'] = econdata['delegacion'] + "," + econdata['tipo']
(econdata['estratificado'].value_counts() / len(econdata)).sort_values(ascending=False)

Con esto ya tenemos los datos por categor铆as (paso 1) y podemos ver su proporci贸n real:

Para nuestro muestreo definimos las siguientes proporciones (paso 2):

  • Cuaut茅moc, Hotel: 0.5,
  • Cuaut茅moc, Museo: 0.2,
  • Venustiano Carranza, Hotel: 0.1,
  • Cuauht茅moc, Mercado: 0.1,
  • Venustiano Carranza, Mercado: 0.1

Para crear dicha proporci贸n a partir de los datos originales se utiliza la siguiente funci贸n que encuentra el n煤mero de muestras necesario de cada categor铆a (paso 3), hace un sampleo simple dentro de dicha categoria y luego junta esas muestras (paso 4):

def data_estratificada(econdata, nombres_columnas_estrat, valores_estrat, prop_estrat, random_state=None):

  df_estrat = pd.DataFrame(columns = econdata.columns) 

  pos = -1
  for i in range(len(valores_estrat)):
    pos += 1
    if pos == len(valores_estrat) - 1: 
      ratio_len = len(econdata) - len(df_estrat)
    else:
      ratio_len = int(len(econdata) * prop_estrat[i])

    df_filtrado = econdata[econdata[nombres_columnas_estrat] ==valores_estrat[i]]
    df_temp = df_filtrado.sample(replace=True, n=ratio_len, random_state=random_state)

    df_estrat = pd.concat([df_estrat, df_temp]) 
  return df_estrat

Utiliza este c贸digo para crear el sampleo:

valores_estrat = ['Cuaut茅moc,Hotel', 'Cuaut茅moc,Museo', 'Venustiano Carranza,Hotel', 'Cuauht茅moc,Mercado','Venustiano Carranza,Mercado']
prop_estrat = [0.5, 0.2, 0.1, 0.1, 0.1]
df_estrat = data_estratificada(econdata, 'estratificado', valores_estrat, prop_estrat, random_state=42)
df_estrat

Adicionalmente, puedes usar este c贸digo para ver la proporci贸n final de tus datos:

(df_estrat['estratificado'].value_counts()/len(df_estrat)).sort_values(ascending=False)

Si todo sali贸 bien, deber铆as ver algo similar a esto:

Con esto ya tienes una muestra en las proporciones que dese谩bamos en un principio.

No me est谩 quedando del todo claro que papel juega el random_state 馃槙

No hab铆a entendido bien el muestreo estratificado, pero al hacer el c贸digo ya lo entend铆 mejor.

  • B谩sicamente es muy 煤til cuando quieres indicar qu茅 proporci贸n de datos de una misma categor铆a quieres obtener.
  • Obtener el mismo muestreo (con las mismas condiciones) gracias al random_state.

Para entender este muestreo vamos a analizar que sucede cuando apliquemos un muestreo aleatorio simple vs un estratificado a los registros de Mercados que se encuentran en la delegacion Venustiano Carranza al cual me referire como el grupo 鈥淢VC鈥 . Escogi el grupo MVS dado que de los 230 registros que tiene nuestro dataset (poblacion) solo el 4.7% (11 registros)son mercados en en la delegacion venustiano carranza, por lo cual es muy sensible a que estos registros desaparezcan al hacer un muestreo aleatorio. en cambio al hacer un estratificado podemos asignar una fraccion a recolectar de cada grupo y asi lograr que el grupo MVC no desaparesca ya que si queremos hacer un muestreo de 40 registros (n = 40) el 4.78% de las muestras seran del grupo MVC osea 1.8 registros que redondeando serian 2. en resumen al hacer un muestro n =40 la probabilidad de que se seleccione un registro del grupo MVC usando un muestreo aleatorio simple es muy bajo siendo probable que no se recoja ningun registro MVC al aplicar el muestreo, pero si en cambio usamos un muestreo estratificado recogeremos al menos 2 registros del grupo.
pd: sin ayuda de la comunidad no hubiera entendido la clase, gracias !

Creo que esta es una alternativa mas clara y menos larga:

data['strat'] = data['delegacion'] + " - " + data['tipo']

def stratified_sample(data, category, size):
  strat_values = data[category].unique()
  strat_props = (data[category].value_counts() / len(data))

  strat_sample = pd.DataFrame(columns = data.columns)

  for value in strat_values:
    strat_sample = pd.concat([strat_sample, data[(data[category] == value)].sample(n = round(strat_props[value]*size)) ])
  
  return strat_sample

strat_sample = stratified_sample(data, 'strat', 40)

Otro curso que se lleva todos los aplausos.

Me pareci贸 un poco complicado el c贸digo de la profesora, por lo que me d铆 la tarea de escribir mi propio c贸digo:

def stratified_sampling(df, col_name, size, random_state=0):
    ratio_df = df[col_name].value_counts() / len(df) 
    
    strat_idx = []
    for val in ratio_df.index:
        n_val = int(ratio_df[val] * len(df)) 
        size_per_val = round(n_val * size)
        strat = df[df[col_name]==val].sample(size_per_val, random_state=random_state)
        strat_idx.append(strat.index)
 
    strat_idx = [i for sublist in strat_idx for i in sublist]

    return df.iloc[strat_idx]

鈥婣qu铆 te doy un ejemplo de c贸mo realizar el muestreo estratificado en Python con la librer铆a pandas:

Copiar c贸digo
import pandas as pd

Crear un dataframe

data = {'Gnero': ['Hombre', 'Mujer', 'Hombre', 'Mujer', 'Hombre', 'Mujer'],
        'Edad': [22, 38, 27, 35, 18, 45],
        'Ingresos': [50000, 100000, 75000, 120000, 90000, 80000]}
df = pd.DataFrame(data)

Crear estratos

strat_df = df.groupby(
strat_df =
'G茅nero').apply(lambda x: x.sample(frac=0.3))

Muestra estratificada

print(strat_df)
  • En este ejemplo, se crea un marco de datos con tres columnas: G茅nero, Edad e Ingresos. Luego, se agrupa el dataframe por la columna 鈥淕茅nero鈥 y se aplica una funci贸n de prueba de forma aleatoria a cada estrato con una fracci贸n de 0.3. El resultado es una muestra estratificada donde el 30% de los elementos de cada estrato son seleccionados al azar.

La librer铆a numpy tambi茅n tiene la funci贸n 鈥榬andom.choice鈥 que permite elegir elementos al azar de una lista o una matriz de una manera similar.

Bueno, me costo mas de lo que me hubiera gustado la verda, pero aca les dejo el reto que hice con una dataset de dibujitos que encontre en kaggle (voy a hacer el muestreo estratificado, ya que los otros son simples dentro de todo :p)


# Creamos una variable nueva en el dataset
df_cartoons['estratificado'] = df_cartoons['Country']+','+df_cartoons['Original Channel']
(df_cartoons['estratificado'].value_counts() / len(df_cartoons)).sort_values(ascending=False)

def data_estratificada(df_cartoons, nombres_columnas_estrat, valores_estrat, prop_estrat, random_state=None):
    
    df_estrat = pd.DataFrame(columns = df_cartoons.columns) # Creamos un data frame vac铆o con los nombres de las columnas de df_cartoons

    pos = -1
    for i in range(len(valores_estrat)): # iteraci贸n sobre los valores estratificados
        pos += 1
        if pos == len(valores_estrat) - 1: 
            ratio_len = len(df_cartoons) - len(df_estrat) # si es la iteraci贸n final calcula el n煤mero de valores de salida tenga el mismo n煤mero de filas que de entrada
        else:
            ratio_len = int(len(df_cartoons) * prop_estrat[i]) # calcula el n煤mero de filas seg煤n la proporci贸n deseada

        df_filtrado = df_cartoons[df_cartoons[nombres_columnas_estrat] ==valores_estrat[i]] # filtra los datos de origen seg煤n los valores seleccionados en la estratificaci贸n de datos
        df_temp = df_filtrado.sample(replace=True, n=ratio_len, random_state=random_state) # haz un sample de los datos filtrados usando la ratio que hemos calculado
        
        df_estrat = pd.concat([df_estrat, df_temp]) # junta las tablas de sample con la estratificada para producir el resultado final
        
    return df_estrat # Return the stratified, re-sampled data  

valores_estrat = ['United States,Netflix', 'United States,Cartoon Network', 'United States,Adult Swim']
prop_estrat = [0.6, 0.3, 0.1]
df_estrat = data_estratificada(df_cartoons, 'estratificado', valores_estrat, prop_estrat, random_state=42)
df_estrat

(df_estrat['estratificado'].value_counts()/len(df_estrat)).sort_values(ascending=False)

Si bien el c贸digo deber铆a funcionar bien, es mejor comprobar el resultado, aqu铆 una peque帽a validaci贸n del objetivo

(df_estrat['estratificado'].value_counts() / len(df_estrat)).sort_values(ascending=False)

Cuaut茅moc,Hotel                0.5
Cuaut茅moc,Museo                0.2
Venustiano Carranza,Hotel      0.1
Cuauht茅moc,Mercado             0.1
Venustiano Carranza,Mercado    0.1
Name: estratificado, dtype: float64

En el contexto de muestreo, el par谩metro 鈥渞andom_state鈥 es utilizado para establecer una semilla para el generador de n煤meros aleatorios utilizado en la selecci贸n de muestras. Esto asegura que los resultados son reproducibles, ya que si utiliza el mismo valor para 鈥渞andom_state鈥 en dos llamadas diferentes, se seleccionar谩n las mismas muestras. Sin embargo, si se utiliza un valor diferente para 鈥渞andom_state鈥 en cada llamada, se seleccionar谩n muestras diferentes.

El siguiente c贸digo me regresa los valores de cada categor铆a ordenados del que mas veces aparece al que menos, seria una forma de reemplazar valores_estrat pero igual generar uno mismo la lista con los valores nos da un mayor control sobre las proporciones que le asignamos a cada categor铆a.

econdata[columna_strat].value_counts().index

Hay una imprecisi贸n: El par谩metro random_state (en este caso 42) la instructora indica que hace que las filas se tomen de 42 en 42 lo cual no tiene nada que ver con su verdadero comportamiento (pueden verificar que las filas no tienen ese intervalo). Lo que hace es servir de semilla para el generador de n煤meros aleatorios y es un par谩metro opcional en la funci贸n sample.

Resultado final:

(df_estrat['estratificado'].value_counts() / len(econdata)).sort_values(ascending=False)

Le hice unos peque帽os cambio al c贸digo, nos permite colocar el tama帽o de la muestra.

def mi_estratificado (datos,columna,size,valores_estrat ,random_state = None):
  df_estrat = pd.DataFrame(columns=datos.columns)
  datos_en_col = datos[columna].unique()
  con = 0
  for i in datos_en_col :
    df_filtrado = datos[datos[columna] == datos_en_col[con]]
    df_temp = df_filtrado.sample(replace=True , n= int(valores_estrat[con] *size) ,random_state= random_state)
    df_estrat = pd.concat([df_estrat,df_temp])
    con += 1
  return df_estrat
### Para Probarlo
val_estrat = [0.5,0.2,0.1,0.1,0.1]
df_p = mi_estratificado(econodata,'estratificado',150,val_estrat, random_state=4)
print((df_p['estratificado'].value_counts()/len(df_p)).sort_values(ascending=False))
df_p

Muy bueno para dar esas proporciones al final y luego hacer otros estudios con los datos resultantes