40 · DataFrame: tablas 2D etiquetadas
Un DataFrame es un diccionario de Series que comparten un índice — el contenedor universal para datos tabulares de ML. Domina la creación, inspección, filtrado y el footgun de SettingWithCopyWarning que tropieza a todo usuario nuevo de Pandas.
Un **DataFrame** es una colección de Series que comparten el mismo índice de fila — como una hoja de cálculo o una tabla SQL, pero viviendo en memoria e interoperable directamente con NumPy. El índice de fila y las etiquetas de columna juntas significan que cada celda tiene una dirección de dos coordenadas: `df.loc[etiqueta_fila, nombre_col]`. Entender que un DataFrame es fundamentalmente un **dict de Series alineadas** desmitifica toda operación de DataFrame: seleccionar una columna devuelve una Series; un filtro booleano crea una Series máscara; añadir una columna es simplemente asignar una nueva clave al dict.
Sin esto:
Sin DataFrames (o herramientas equivalentes), cada paso de preprocesamiento — filtrar filas, computar columnas derivadas, seleccionar subsets de features — requeriría escribir bucles explícitos sobre arrays NumPy crudos y rastrear manualmente los nombres de columnas mediante listas separadas. El DataFrame te da columnas nombradas, alineación por etiqueta de fila y operaciones estilo SQL (seleccionar, filtrar, unir, agrupar) en un solo objeto. Es la principal razón por la que Python desplazó a R como el lenguaje de ML por defecto.
Un DataFrame es el caballo de batalla 2D de pandas. Internamente es un dict de objetos Series que comparten el mismo índice de fila. Puedes pensar en él como una hoja de cálculo en RAM.
Las formas más comunes de crear un DataFrame:
# De un dict de listas — cada clave se convierte en nombre de columna
pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})
# De una lista de dicts — cada dict es una fila
pd.DataFrame([{'name': 'alice', 'age': 30}, {'name': 'bob', 'age': 25}])
Métodos de inspección clave a ejecutar en cualquier nuevo dataset:
.head(n)/.tail(n)— primeras/últimas n filas (por defecto 5).shape— tupla(n_filas, n_cols).info()— nombres de columnas, dtypes, conteos no nulos, uso de memoria.describe()— estadísticas resumen para columnas numéricas.dtypes— Series de dtype por columna.columns— Index de nombres de columnas
Acceso a columnas:
df['col']— devuelve una Series (siempre seguro)df[['col']]— devuelve un DataFrame de una sola columna (dobles corchetes)df.col— acceso por atributo — evítalo en código nuevo: falla cuando los nombres de columna contienen espacios o colisionan con nombres de métodos comodf.count.
Python (in browser)
`.describe()` es el primer comando a ejecutar en cualquier nuevo dataset numérico. Muestra count, mean, std, min, cuartiles y max en una sola llamada — suficiente para detectar outliers (max muy lejos de la media), discrepancias de escala (edad en años vs compras en millones) y columnas constantes (std ≈ 0) antes de dedicar tiempo al entrenamiento del modelo.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`df['age'] > 30` produce una Series booleana (la máscara). Pasar esa máscara de vuelta a `df[máscara]` devuelve solo las filas donde la máscara es `True`. Encadenar `[['name', 'purchases']]` (dobles corchetes) selecciona dos columnas como DataFrame. Este patrón — filtrar filas, luego seleccionar columnas — es la base de toda operación de subconjunto de datos en una pipeline de preprocesamiento.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
Asignar a `df['nueva_col']` añade (o sobreescribe) una columna en el lugar. El lado derecho puede ser un escalar, una lista, un array NumPy o una Series — pandas alinea por índice automáticamente. Esta es la forma estándar de crear nuevos features antes del entrenamiento del modelo.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
`.loc[máscara_fila, nombre_col] = valor` es el único idioma seguro para asignación condicional. Resuelve tanto la selección de filas como la asignación de columna en una sola operación de indexación, por lo que pandas siempre modifica el DataFrame original. El indexado encadenado (`df[mask]['col'] = ...`) es el footgun más común de Pandas — falla silenciosamente o advierte dependiendo de si el resultado intermedio es una vista o una copia.
¿Cuál es la diferencia entre `df['col']` y `df[['col']]`?
- Un DataFrame es un dict de Series alineadas que comparten el mismo índice de fila. Cada columna es una Series; el shape es `(n_filas, n_cols)`.
- `.head()`, `.describe()`, `.info()`, `.dtypes` son los primeros cuatro comandos de inspección en cualquier nuevo dataset.
- `df['col']` devuelve una Series; `df[['col']]` devuelve un DataFrame de una sola columna. `df[máscara_bool]` filtra filas.
- Usa `df.loc[máscara_fila, 'col'] = valor` para asignación condicional — nunca encadenes `df[mask]['col'] = valor` (SettingWithCopyWarning).
Todo dataset de ML supervisado comienza como un DataFrame. `df[features]` (dobles corchetes, lista de nombres de columna) extrae la matriz 2D `X`; `df[target]` (corchete simple) extrae el vector 1D `y`. `df.describe()` es el primer paso obligatorio de cualquier EDA. Filtrar con máscaras booleanas es cómo divides los conjuntos de entrenamiento/validación antes de `train_test_split`.
Si lo quitas: Sin DataFrames, mantener la correspondencia entre los valores de los features y sus nombres de columna requeriría una lista paralela de strings — fácilmente rota al ordenar, filtrar o añadir columnas. Pasar arrays sin etiquetas a scikit-learn es legal pero elimina toda interpretabilidad: `coef_[3]` no significa nada; `coef_[df.columns[3]]` significa 'el coeficiente para la edad'. Los DataFrames mantienen los metadatos vivos a lo largo de la pipeline.