En este tutorial, diseñamos una canalización de modelado y análisis de estilo de producción de extremo a extremo utilizando Vaex para operar de manera eficiente en millones de filas sin materializar datos en la memoria. Generamos un conjunto de datos realista a gran escala, diseñamos características ricas de comportamiento y a nivel de ciudad utilizando expresiones perezosas y estadísticas aproximadas, y agregamos conocimientos a escala. Luego integramos Vaex con scikit-learn para entrenar y evaluar un modelo predictivo, demostrando cómo Vaex puede actuar como columna vertebral para análisis exploratorios de alto rendimiento y flujos de trabajo de aprendizaje automático.
Generamos un conjunto de datos sintéticos grande y realista e inicializamos un Vaex DataFrame para trabajar de forma perezosa en millones de filas. Diseñamos características numéricas centrales directamente como expresiones para que no se materialicen datos intermedios. Validamos la configuración inspeccionando el esquema, el recuento de filas y una pequeña muestra de valores calculados.
inv_city_map = {v:k para k,v en city_map.items()} n_cities = len(city_map) p95_ingresos_k_by_city = df.percentile_approx(“ingresos_k”, 95, binby=”label_encoded_city”, forma=n_ciudades, límites=[-0.5, n_cities-0.5]) p50_value_by_city = df.percentile_approx(“value_score”, 50, binby=”label_encoded_city”, forma=n_ciudades, límites=[-0.5, n_cities-0.5]) avg_ingresos_k_by_ciudad = df.mean(“ingresos_k”, binby=”label_encoded_city”, forma=n_ciudades, límites=[-0.5, n_cities-0.5]) target_rate_by_city = df.mean(“target”, binby=”label_encoded_city”, forma=n_ciudades, límites=[-0.5, n_cities-0.5]) n_by_city = df.count(binby=”label_encoded_city”, forma=n_ciudades, límites=[-0.5, n_cities-0.5]) p95_ingresos_k_por_ciudad = np.asarray(p95_ingresos_k_por_ciudad).reshape(-1) p50_valor_por_ciudad = np.asarray(p50_valor_por_ciudad).reforma(-1) avg_ingresos_k_por_ciudad = np.asarray(avg_ingresos_k_por_ciudad).reshape(-1) target_rate_by_city = np.asarray(target_rate_by_city).reshape(-1) n_by_city = np.asarray(n_by_city).reshape(-1) city_table = pd.DataFrame({ “city_id”: np.arange(n_cities), “ciudad”: [inv_city_map[i] para i en rango (n_ciudades)]”n”: n_by_city.astype(“int64”), “avg_ Income_k”: avg_Ingresos_k_by_city, “p95_Ingresos_k”: p95_Ingresos_k_by_city, “median_value_score”: p50_value_by_city, “target_rate”: target_rate_by_city }).sort_values([“target_rate”,”p95_income_k”]ascendente=False) print(“\nResumen de la ciudad:”) print(city_table.to_string(index=False)) df_city_features = vaex.from_pandas(city_table[[“city”,”p95_income_k”,”avg_income_k”,”median_value_score”,”target_rate”]], copy_index=False) df = df.join(df_city_features, on=”ciudad”, rsuffix=”_city”) df[“income_vs_city_p95”] = df.ingresos_k / (df.p95_ingresos_k + 1e-9) df[“value_vs_city_median”] = df.value_score – df.median_value_score
Codificamos datos categóricos de la ciudad y calculamos estadísticas escalables y aproximadas por ciudad mediante operaciones basadas en agrupamiento. Reunimos estos agregados en una tabla a nivel de ciudad y los unimos nuevamente al conjunto de datos principal. Luego derivamos características relativas que comparan cada registro con el contexto de su ciudad.
“age”,”tenure_y”,”tx”,”income_k”,”log_income”,”tx_per_year”,”value_score”,
“p95_income_k”,”avg_income_k”,”median_value_score”,”target_rate”,
“income_vs_city_p95″,”value_vs_city_median”
]
escalador = vaex.ml.StandardScaler(features=features_num, with_mean=True, with_std=True, prefix=”z_”) df = scaler.fit_transform(df) características = [“z_”+f for f in features_num] + [“label_encoded_city”]
df_train, df_test = df.split_random([0.80, 0.20]random_state=42) model = LogisticRegression(max_iter=250, solver=”lbfgs”, n_jobs=None) vaex_model = Predictor(modelo=modelo, características=características, target=”target”, predict_name=”pred”) t0 = time.time() vaex_model.fit(df=df_train) fit_s = time.time() – t0 df_test = vaex_model.transform(df_test) y_true = df_test[“target”].to_numpy() y_pred = df_test[“pred”].to_numpy() auc = roc_auc_score(y_true, y_pred) ap = Average_precision_score(y_true, y_pred) print(“\nModel:”) print(“fit_segundos:”, round(fit_s, 3)) print(“test_auc:”, round(float(auc), 4)) print(“test_avg_precision:”, redondo(flotador(ap), 4))
Estandarizamos todas las características numéricas utilizando las utilidades ML de Vaex y preparamos un vector de características consistente para el modelado. Dividimos el conjunto de datos sin cargar todo el conjunto de datos en la memoria. Entrenamos un modelo de regresión logística a través del contenedor sklearn de Vaex y evaluamos su rendimiento predictivo.
Analizamos el comportamiento del modelo segmentando las predicciones en deciles y calculando métricas de elevación. Calculamos las tasas de referencia y las comparamos entre grupos de puntuación para evaluar la calidad de la clasificación. Resumimos los resultados en una mesa elevadora compacta que refleja los diagnósticos de modelos del mundo real.
export_cols = bases_cols + [“z_”+f for f in features_num]
df_export = df[export_cols].sample(n=500_000, random_state=1) if os.path.exists(parquet_path): os.remove(parquet_path) df_export.export_parquet(parquet_path) pipeline_state = { “vaex_version”: vaex.__version__, “encoder_labels”: {k: {str(kk): int(vv) for kk,vv in v.items()} para k,v en encoder.labels_.items()}, “scaler_mean”: [float(x) for x in scaler.mean_]”escalador_std”: [float(x) for x in scaler.std_]”features_num”: características_num, “export_cols”: export_cols, } con open(state_path, “w”) como f: json.dump(pipeline_state, f) df_reopen = vaex.open(parquet_path) df_reopen[“income_k”] = df_reopen.ingresos / 1000.0 df_reopen[“tenure_y”] = df_reopen.tenure_m / 12.0 df_reopen[“log_income”] = df_reopen.ingresos.log1p() df_reopen[“tx_per_year”] = df_reopen.tx / (df_reopen.tenure_y + 0.25) df_reopen[“value_score”] = (0,35*df_reopen.log_ingresos + 0,20*df_reopen.tx_per_year + 0,10*df_reopen.tenure_y – 0,015*df_reopen.age) df_city_features = vaex.from_pandas(city_table[[“city”,”p95_income_k”,”avg_income_k”,”median_value_score”,”target_rate”]], copy_index=False) df_reopen = df_reopen.join(df_city_features, on=”ciudad”, rsuffix=”_city”) df_reopen[“income_vs_city_p95”] = df_reopen.ingresos_k / (df_reopen.p95_ingresos_k + 1e-9) df_reopen[“value_vs_city_median”] = df_reopen.value_score – df_reopen.median_value_score con open(state_path, “r”) como f: st = json.load(f) etiquetas_city = {k: int(v) para k,v en st[“encoder_labels”][“city”].items()} df_reopen[“label_encoded_city”] = df_reopen.city.map(labels_city, default_value=-1) para i, hazaña en enumerar(st[“features_num”]): media_i = st[“scaler_mean”][i]
std_i = st[“scaler_std”][i] si st[“scaler_std”][i] != 0 más 1.0 df_reopen[“z_”+feat] = (df_reabrir[feat] – mean_i) / std_i df_reopen = vaex_model.transform(df_reopen) print(“\nArtefactos escritos:”) print(parquet_path) print(state_path) print(“\nPredicciones de parquet reabiertas (cabeza):”) print(df_reopen[[“city”,”income_k”,”value_score”,”pred”,”target”]].head(8)) print(“\nListo.”)
Exportamos una muestra grande con todas las funciones a Parquet y conservamos el estado de preprocesamiento completo para lograr reproducibilidad. Recargamos los datos y reconstruimos de manera determinista todas las funciones diseñadas a partir de metadatos guardados. Realizamos inferencias en el conjunto de datos recargado para confirmar que la canalización permanece estable y se puede implementar de un extremo a otro.
En conclusión, demostramos cómo Vaex permite un procesamiento de datos rápido y eficiente en la memoria y al mismo tiempo admite ingeniería de funciones avanzadas, agregación e integración de modelos. Demostramos que las estadísticas aproximadas, el cálculo diferido y la ejecución fuera del núcleo nos permiten escalar limpiamente desde el análisis hasta los artefactos listos para la implementación. Al exportar características reproducibles y conservar el estado completo de la canalización, cerramos el ciclo desde los datos sin procesar hasta la inferencia, lo que ilustra cómo Vaex encaja naturalmente en los flujos de trabajo modernos de Python con grandes datos.
Consulte los códigos completos aquí. Además, no dude en seguirnos en Twitter y no olvide unirse a nuestro SubReddit de más de 120.000 ML y suscribirse a nuestro boletín. ¡Esperar! estas en telegrama? Ahora también puedes unirte a nosotros en Telegram.