Bien que DataStore soit largement compatible avec pandas, il existe des différences importantes à connaître.
Tableau récapitulatif
| Aspect | pandas | DataStore |
|---|---|---|
| Exécution | immédiat (immédiate) | différé (différée) |
| Types de retour | DataFrame/Series | DataStore/ColumnExpr |
| Ordre des lignes | Préservé | Préservé (automatiquement) ; non garanti en mode performance |
| inplace | Pris en charge | Non pris en charge |
| Index | Entièrement pris en charge | Simplifié |
| Mémoire | Toutes les données en mémoire | Données conservées à la source |
1. Exécution différée vs immédiate
pandas (immédiat)
Les opérations s’exécutent immédiatement :
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 (différé)
Les opérations sont reportées jusqu’au moment où les résultats sont nécessaires :
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 pandasPourquoi c’est important
L’exécution différée permet :
- Optimisation des requêtes : plusieurs opérations sont compilées en une seule requête SQL
- Sélection des colonnes utiles : seules les colonnes nécessaires sont lues
- Application des filtres à la source : les filtres sont appliqués à la source
- Utilisation efficace de la mémoire : ne chargez pas les données dont vous n’avez pas besoin
2. Types de retour
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 LazyGroupByConversion vers les types 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. Déclencheurs d’exécution
DataStore s’exécute lorsque vous avez besoin des valeurs effectives :
| Déclencheur | Exemple | Remarques |
|---|---|---|
print() / repr() |
print(ds) |
L’affichage requiert des données |
len() |
len(ds) |
Requiert le nombre de lignes |
.columns |
ds.columns |
Requiert les noms de colonnes |
.dtypes |
ds.dtypes |
Requiert les informations de type |
.shape |
ds.shape |
Requiert les dimensions |
.values |
ds.values |
Requiert les données effectives |
.index |
ds.index |
Requiert l’index |
to_df() |
ds.to_df() |
Conversion explicite |
| Itération | for row in ds |
Requiert une itération |
equals() |
ds.equals(other) |
Requiert une comparaison |
Opérations qui restent différées
| Opération | Renvoie |
|---|---|
filter() |
DataStore |
select() |
DataStore |
sort() |
DataStore |
groupby() |
LazyGroupBy |
join() |
DataStore |
ds['col'] |
ColumnExpr |
ds[['a', 'b']] |
DataStore |
ds[condition] |
DataStore |
4. Ordre des lignes
pandas
L’ordre des lignes est toujours conservé :
df = pd.read_csv("data.csv")
print(df.head()) # Always same order as fileDataStore
L’ordre des lignes est automatiquement conservé pour la plupart des opérations :
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 enregistre automatiquement en interne la position d’origine des lignes (à l’aide de rowNumberInAllBlocks()) afin de garantir un ordre cohérent avec pandas.
Lorsque l’ordre est préservé
- Sources basées sur des fichiers (CSV, Parquet, JSON, etc.)
- Sources de type pandas DataFrame
- Opérations de filtrage
- Sélection de colonnes
- Après utilisation explicite de
sort()ousort_values() - Opérations qui définissent l’ordre (
nlargest(),nsmallest(),head(),tail())
Quand l’ordre peut différer
- Après les agrégations
groupby()(utilisezsort_values()pour garantir un ordre cohérent) - Après
merge()/join()avec certains types de JOIN - En mode performance (
config.use_performance_mode()) : l’ordre des lignes n’est pas garanti, quelle que soit l’opération. Voir Mode Performance.
5. Pas de paramètre 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’est pas pris en charge. Affectez toujours le résultat :
ds = ds.drop(columns=['col']) # Returns new DataStore
ds = ds.fillna(0) # Returns new DataStore
ds = ds.rename(columns={'old': 'new'}) # Returns new DataStorePourquoi pas d’inplace ?
DataStore s’appuie sur des opérations immuables, ce qui permet :
- La construction de requêtes (évaluation différée)
- Une meilleure sûreté en multithreading
- Un débogage simplifié
- Un code plus propre
6. Prise en charge des index
pandas
Prise en charge complète des index :
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
Gestion simplifiée des index :
# 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']Le type de source du DataStore est important
- Source DataFrame : conserve l’index pandas
- Source File : utilise un index entier simple
7. Comportement des comparaisons
Comparaison avec pandas
pandas ne reconnaît pas les objets 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()) # TrueUtiliser equals()
# DataStore.equals() also works
dsf.equals(pdf) # Compares with pandas DataFrame8. Inférence de types
pandas
Utilise les types numpy/pandas :
df['col'].dtype # int64, float64, object, datetime64, etc.DataStore
Peut utiliser des types 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 typeConversion explicite de type
# Force specific type
ds['col'] = ds['col'].astype('int64')9. Modèle mémoire
pandas
Toutes les données sont en mémoire :
df = pd.read_csv("huge.csv") # 10GB in memory!DataStore
Les données restent à la source jusqu’à ce qu’elles soient nécessaires :
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. Messages d’erreur
Différentes sources d’erreurs
- erreurs pandas : issues de la bibliothèque pandas
- erreurs DataStore : issues de chDB ou de ClickHouse
# May see ClickHouse-style errors
# "Code: 62. DB::Exception: Syntax error..."Conseils de débogage
# 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 migration
Lors d’une migration depuis pandas :
- Modifier l’instruction d’import
- Supprimer les paramètres
inplace=True - Ajouter explicitement
to_df()lorsqu’un pandas DataFrame est requis - Ajouter un tri si l’ordre des lignes est important
- Utiliser
to_pandas()pour les tests de comparaison - Tester avec des volumes de données représentatifs
Référence rapide
| pandas | DataStore |
|---|---|
df[condition] |
Identique (renvoie un DataStore) |
df.groupby() |
Identique (renvoie un 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) |
Identique (déclenche l’exécution) |
len(df) |
Identique (déclenche l’exécution) |