Embora o DataStore seja altamente compatível com o pandas, há diferenças importantes que precisam ser compreendidas.
Tabela-resumo
| Aspecto | pandas | DataStore |
|---|---|---|
| Execução | Imediata | preguiçosa (adiada) |
| Tipos de retorno | DataFrame/Series | DataStore/ColumnExpr |
| Ordem das linhas | Preservada | Preservada (automaticamente); não garantida no modo de desempenho |
| inplace | Suportado | Não suportado |
| Índice | Suporte completo | Simplificado |
| Memória | Todos os dados na memória | Dados na fonte |
1. Execução preguiçosa vs imediata
pandas (Execução imediata)
As operações são executadas imediatamente:
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 (preguiçoso)
As operações são postergadas até que os resultados sejam necessários:
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 que isso importa
A execução preguiçosa permite:
- Otimização de consultas: várias operações são compiladas em uma única consulta SQL
- Poda de colunas: apenas as colunas necessárias são lidas
- Pushdown de filtros: os filtros são aplicados na origem
- Eficiência no uso de memória: não carregue dados desnecessários
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 LazyGroupByConvertendo para os tipos do 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. Gatilhos de execução
O DataStore é executado quando você precisa de valores reais:
| Gatilho | Exemplo | Observações |
|---|---|---|
print() / repr() |
print(ds) |
A exibição requer dados |
len() |
len(ds) |
Requer a contagem de linhas |
.columns |
ds.columns |
Requer nomes de colunas |
.dtypes |
ds.dtypes |
Requer informações de tipo |
.shape |
ds.shape |
Requer dimensões |
.values |
ds.values |
Requer os dados reais |
.index |
ds.index |
Requer o índice |
to_df() |
ds.to_df() |
Conversão explícita |
| Iteração | for row in ds |
Requer iteração |
equals() |
ds.equals(other) |
Requer comparação |
Operações que permanecem preguiçosas
| Operação | Retorna |
|---|---|
filter() |
DataStore |
select() |
DataStore |
sort() |
DataStore |
groupby() |
LazyGroupBy |
join() |
DataStore |
ds['col'] |
ColumnExpr |
ds[['a', 'b']] |
DataStore |
ds[condition] |
DataStore |
4. Ordem das linhas
pandas
A ordem das linhas é sempre preservada:
df = pd.read_csv("data.csv")
print(df.head()) # Always same order as fileDataStore
A ordem das linhas é preservada automaticamente na maioria das operações:
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 rastreia automaticamente, internamente, as posições originais das linhas (usando rowNumberInAllBlocks()) para garantir que a ordem permaneça consistente com o pandas.
Quando a ordem é preservada
- Fontes de arquivo (CSV, Parquet, JSON etc.)
- Fontes de DataFrame do pandas
- Operações de filtro
- Seleção de colunas
- Após o uso explícito de
sort()ousort_values() - Operações que definem a ordem (
nlargest(),nsmallest(),head(),tail())
Quando a ordem pode variar
- Após agregações
groupby()(usesort_values()para garantir uma ordem consistente) - Após
merge()/join()com determinados tipos de join - No modo de desempenho (
config.use_performance_mode()): a ordem das linhas não é garantida em nenhuma operação. Veja Modo de desempenho.
5. Sem o 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 não é suportado. Sempre atribua o resultado:
ds = ds.drop(columns=['col']) # Returns new DataStore
ds = ds.fillna(0) # Returns new DataStore
ds = ds.rename(columns={'old': 'new'}) # Returns new DataStorePor que não inplace?
DataStore usa operações imutáveis para permitir:
- Construção de consultas (lazy evaluation)
- Segurança em ambientes multithread
- Depuração facilitada
- Código mais limpo
6. Suporte a índices
pandas
Suporte completo a í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
Suporte simplificado a í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']A origem do DataStore faz diferença
- Origem DataFrame: preserva o índice do pandas
- Origem File: usa um índice inteiro simples
7. Comportamento das comparações
Comparação com o pandas
O pandas não reconhece 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()) # TrueComo usar equals()
# DataStore.equals() also works
dsf.equals(pdf) # Compares with pandas DataFrame8. Inferência de tipos
pandas
Usa tipos do numpy/pandas:
df['col'].dtype # int64, float64, object, datetime64, etc.DataStore
Pode usar tipos do 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 typeConversão de tipo explícita
# Force specific type
ds['col'] = ds['col'].astype('int64')9. Modelo de memória
pandas
Todos os dados ficam na memória:
df = pd.read_csv("huge.csv") # 10GB in memory!DataStore
Os dados permanecem na origem até que sejam necessários:
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. Mensagens de erro
Diferentes fontes de erros
- erros do pandas: Da biblioteca pandas
- erros do DataStore: Do chDB ou do ClickHouse
# May see ClickHouse-style errors
# "Code: 62. DB::Exception: Syntax error..."Dicas de depuração
# 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()Checklist de migração
Ao migrar a partir do pandas:
- Altere a instrução de importação
- Remova os parâmetros
inplace=True - Adicione
to_df()explicitamente onde um DataFrame do pandas for necessário - Adicione ordenação se a ordem das linhas for importante
- Use
to_pandas()em testes de comparação - Teste com volumes de dados representativos
Referência rápida
| pandas | DataStore |
|---|---|
df[condition] |
O mesmo (retorna DataStore) |
df.groupby() |
O mesmo (retorna 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) |
O mesmo (dispara a execução) |
len(df) |
O mesmo (dispara a execução) |