Aunque DataStore es muy compatible con pandas, hay diferencias importantes que conviene entender.
Tabla resumen
| Aspecto | pandas | DataStore |
|---|---|---|
| Ejecución | Inmediata | Diferida |
| Tipos de retorno | DataFrame/Series | DataStore/ColumnExpr |
| Orden de las filas | Se conserva | Se conserva (automáticamente); no está garantizado en modo de rendimiento |
| inplace | Compatible | No compatible |
| Índice | Compatibilidad total | Simplificado |
| Memoria | Todos los datos en memoria | Datos en origen |
1. Ejecución diferida vs inmediata
pandas (ejecución inmediata)
Las operaciones se ejecutan de inmediato:
import pandas as pd
df = pd.read_csv("data.csv") # Loads entire file NOW
result = df[df['age'] > 25] # Filters NOW
grouped = result.groupby('city')['salary'].mean() # Aggregates NOWDataStore (Diferido)
Las operaciones se aplazan hasta que se necesitan los resultados:
from chdb import datastore as pd
ds = pd.read_csv("data.csv") # Just records the source
result = ds[ds['age'] > 25] # Just records the filter
grouped = result.groupby('city')['salary'].mean() # Just records
# Execution happens here:
print(grouped) # Executes when displaying
df = grouped.to_df() # Or when converting to pandasPor qué es importante
La ejecución diferida permite:
- Optimización de consultas: varias operaciones se compilan en una sola consulta SQL
- Poda de columnas: solo se leen las columnas necesarias
- Pushdown de filtros: los filtros se aplican en el origen
- Uso eficiente de la memoria: no se cargan datos innecesarios
2. Tipos de retorno
pandas
df['col'] # Returns pd.Series
df[['a', 'b']] # Returns pd.DataFrame
df[df['x'] > 10] # Returns pd.DataFrame
df.groupby('x') # Returns DataFrameGroupByDataStore
ds['col'] # Returns ColumnExpr (lazy)
ds[['a', 'b']] # Returns DataStore (lazy)
ds[ds['x'] > 10] # Returns DataStore (lazy)
ds.groupby('x') # Returns LazyGroupByConversión a tipos de pandas
# Get pandas DataFrame
df = ds.to_df()
df = ds.to_pandas()
# Get pandas Series from column
series = ds['col'].to_pandas()
# Or trigger execution
print(ds) # Automatically converts for display3. Activadores de ejecución
DataStore se ejecuta cuando se necesitan valores reales:
| Activador | Ejemplo | Notas |
|---|---|---|
print() / repr() |
print(ds) |
Mostrarlo requiere datos |
len() |
len(ds) |
Requiere el recuento de filas |
.columns |
ds.columns |
Requiere nombres de columnas |
.dtypes |
ds.dtypes |
Requiere información de tipos |
.shape |
ds.shape |
Requiere dimensiones |
.values |
ds.values |
Requiere los datos reales |
.index |
ds.index |
Requiere el índice |
to_df() |
ds.to_df() |
Conversión explícita |
| Iteración | for row in ds |
Requiere iterar |
equals() |
ds.equals(other) |
Requiere comparación |
Operaciones que permanecen diferidas
| Operación | Devuelve |
|---|---|
filter() |
DataStore |
select() |
DataStore |
sort() |
DataStore |
groupby() |
LazyGroupBy |
join() |
DataStore |
ds['col'] |
ColumnExpr |
ds[['a', 'b']] |
DataStore |
ds[condition] |
DataStore |
4. Orden de filas
pandas
El orden de las filas siempre se mantiene:
df = pd.read_csv("data.csv")
print(df.head()) # Always same order as fileDataStore
El orden de las filas se conserva automáticamente en la mayoría de las operaciones:
ds = pd.read_csv("data.csv")
print(ds.head()) # Matches file order
# Filter preserves order
ds_filtered = ds[ds['age'] > 25] # Same order as pandasDataStore realiza un seguimiento automático de las posiciones originales de las filas a nivel interno (mediante rowNumberInAllBlocks()) para garantizar la coherencia del orden con pandas.
Cuando se mantiene el orden
- Fuentes de archivo (CSV, Parquet, JSON, etc.)
- Fuentes de pandas DataFrame
- Operaciones de filtro
- Selección de columnas
- Después de llamar explícitamente a
sort()osort_values() - Operaciones que definen el orden (
nlargest(),nsmallest(),head(),tail())
Cuándo puede variar el orden
- Después de las agregaciones de
groupby()(usasort_values()para garantizar un orden consistente) - Después de
merge()/join()con ciertos tipos de join - En modo de rendimiento (
config.use_performance_mode()): el orden de las filas no está garantizado en ninguna operación. Consulta Performance Mode.
5. Sin el parámetro inplace
pandas
df.drop(columns=['col'], inplace=True) # Modifies df
df.fillna(0, inplace=True) # Modifies df
df.rename(columns={'old': 'new'}, inplace=True)DataStore
inplace=True no es compatible. Asigne siempre el resultado:
ds = ds.drop(columns=['col']) # Returns new DataStore
ds = ds.fillna(0) # Returns new DataStore
ds = ds.rename(columns={'old': 'new'}) # Returns new DataStore¿Por qué no existe inplace?
DataStore usa operaciones inmutables para permitir:
- La creación de consultas (evaluación diferida)
- Seguridad en entornos multihilo
- Depuración más sencilla
- Código más limpio
6. Compatibilidad con índices
pandas
Compatibilidad completa con índices:
df = df.set_index('id')
df.loc['user123'] # Label-based access
df.loc['a':'z'] # Label-based slicing
df.reset_index()
df.index.name = 'user_id'DataStore
Soporte simplificado para índices:
# Basic operations work
ds.loc[0:10] # Integer position
ds.iloc[0:10] # Same as loc for DataStore
# For pandas-style index operations, convert first
df = ds.to_df()
df = df.set_index('id')
df.loc['user123']La fuente de DataStore es importante
- Fuente de DataFrame: Conserva el índice de pandas
- Fuente de File: Usa un índice entero simple
7. Comportamiento de las comparaciones
Comparación con pandas
pandas no reconoce los objetos DataStore:
import pandas as pd
from chdb import datastore as ds
pdf = pd.DataFrame({'a': [1, 2, 3]})
dsf = ds.DataFrame({'a': [1, 2, 3]})
# This doesn't work as expected
pdf == dsf # pandas doesn't know DataStore
# Solution: convert DataStore to pandas
pdf.equals(dsf.to_pandas()) # TrueUso de equals()
# DataStore.equals() also works
dsf.equals(pdf) # Compares with pandas DataFrame8. Inferencia de tipos
pandas
Usa tipos de numpy/pandas:
df['col'].dtype # int64, float64, object, datetime64, etc.DataStore
Puede utilizar tipos de ClickHouse:
ds['col'].dtype # Int64, Float64, String, DateTime, etc.
# Types are converted when going to pandas
df = ds.to_df()
df['col'].dtype # Now pandas typeConversión explícita de tipos
# Force specific type
ds['col'] = ds['col'].astype('int64')9. Modelo de memoria
pandas
Todos los datos se almacenan en memoria:
df = pd.read_csv("huge.csv") # 10GB in memory!DataStore
Los datos permanecen en su origen hasta que se necesitan:
ds = pd.read_csv("huge.csv") # Just metadata
ds = ds.filter(ds['year'] == 2024) # Still just metadata
# Only filtered result is loaded
df = ds.to_df() # Maybe only 1GB now10. Mensajes de error
Diferentes fuentes de errores
- errores de pandas: De la biblioteca pandas
- errores de DataStore: De chDB o ClickHouse
# May see ClickHouse-style errors
# "Code: 62. DB::Exception: Syntax error..."Consejos de depuración
# View the SQL to debug
print(ds.to_sql())
# See execution plan
ds.explain()
# Enable debug logging
from chdb.datastore.config import config
config.enable_debug()Lista de comprobación de migración
Al migrar desde pandas:
- Cambia la instrucción de importación
- Elimina los parámetros
inplace=True - Añade una llamada explícita a
to_df()cuando se requiera un pandas DataFrame - Añade ordenación si el orden de las filas es importante
- Usa
to_pandas()para pruebas comparativas - Haz pruebas con tamaños de datos representativos
Referencia rápida
| pandas | DataStore |
|---|---|
df[condition] |
Igual (devuelve DataStore) |
df.groupby() |
Igual (devuelve LazyGroupBy) |
df.drop(inplace=True) |
ds = ds.drop() |
df.equals(other) |
ds.to_pandas().equals(other) |
df.loc['label'] |
ds.to_df().loc['label'] |
print(df) |
Igual (activa la ejecución) |
len(df) |
Igual (activa la ejecución) |