Перейти к основному содержимому
Перейти к основному содержимому

Ключевые отличия от pandas

Хотя DataStore в значительной степени совместим с pandas, важно понимать некоторые важные отличия.

Сводная таблица

АспектpandasDataStore
ВыполнениеРаннее (немедленное)Отложенное (ленивое)
Типы возвращаемых значенийDataFrame/SeriesDataStore/ColumnExpr
Порядок строкСохраняетсяСохраняется (автоматически); не гарантируется в режиме производительности
inplaceПоддерживаетсяНе поддерживается
ИндексПолная поддержкаУпрощённая
ПамятьВсе данные в памятиДанные остаются у источника

1. Ленивое vs немедленное выполнение

pandas (жадное выполнение)

Операции выполняются немедленно:

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 NOW

DataStore (ленивый режим)

Операции выполняются только тогда, когда требуются результаты.

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 pandas

Почему это важно

Ленивое выполнение позволяет:

  • Оптимизацию запросов: несколько операций объединяются в один SQL-запрос
  • Отсечение столбцов: считываются только необходимые столбцы
  • Проталкивание фильтров: фильтры применяются на стороне источника данных
  • Более эффективное использование памяти: данные, которые не нужны, не загружаются

2. Типы возвращаемых значений

pandas

df['col']           # Returns pd.Series
df[['a', 'b']]      # Returns pd.DataFrame
df[df['x'] > 10]    # Returns pd.DataFrame
df.groupby('x')     # Returns DataFrameGroupBy

Хранилище данных (DataStore)

ds['col']           # Returns ColumnExpr (lazy)
ds[['a', 'b']]      # Returns DataStore (lazy)
ds[ds['x'] > 10]    # Returns DataStore (lazy)
ds.groupby('x')     # Returns LazyGroupBy

Преобразование в типы данных 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 display

3. Триггеры выполнения

DataStore выполняет вычисления, когда вам нужны фактические значения:

ТриггерПримерПримечания
print() / repr()print(ds)Для отображения нужны данные
len()len(ds)Нужно количество строк
.columnsds.columnsНужны имена столбцов
.dtypesds.dtypesНужна информация о типах
.shapeds.shapeНужны размеры
.valuesds.valuesНужны фактические данные
.indexds.indexНужен индекс
to_df()ds.to_df()Явное преобразование
Итерацияfor row in dsНужно итерироваться
equals()ds.equals(other)Нужно сравнение

Операции, выполняемые лениво

ОперацияВозвращает
filter()DataStore
select()DataStore
sort()DataStore
groupby()LazyGroupBy
join()DataStore
ds['col']ColumnExpr
ds[['a', 'b']]DataStore
ds[condition]DataStore

4. Порядок строк

pandas

Порядок строк всегда сохраняется:

df = pd.read_csv("data.csv")
print(df.head())  # Always same order as file

DataStore

Порядок строк автоматически сохраняется при большинстве операций:

ds = pd.read_csv("data.csv")
print(ds.head())  # Matches file order

# Filter preserves order
ds_filtered = ds[ds['age'] > 25]  # Same order as pandas

DataStore автоматически отслеживает исходные позиции строк во внутреннем представлении (используя rowNumberInAllBlocks()), чтобы порядок соответствовал порядку в pandas.

Когда порядок сохраняется

  • Источники из файлов (CSV, Parquet, JSON и т. д.)
  • Источники pandas DataFrame
  • Операции фильтрации
  • Выбор столбцов
  • После явного вызова sort() или sort_values()
  • Операции, задающие порядок (nlargest(), nsmallest(), head(), tail())

Когда порядок может отличаться

  • После агрегаций с groupby() (используйте sort_values() для обеспечения детерминированного порядка)
  • После merge() / join() с определёнными типами соединений
  • В режиме производительности (config.use_performance_mode()): порядок строк не гарантируется ни для каких операций. См. Режим производительности.

5. Отсутствие параметра 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 не поддерживается. Всегда присваивайте результат:

ds = ds.drop(columns=['col'])           # Returns new DataStore
ds = ds.fillna(0)                       # Returns new DataStore
ds = ds.rename(columns={'old': 'new'})  # Returns new DataStore

Почему нет inplace?

DataStore использует неизменяемые операции для:

  • построения запросов (ленивое вычисление)
  • потокобезопасности
  • более простой отладки
  • более чистого кода

6. Поддержка индексов

pandas

Полная поддержка индексов:

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

Упрощённая поддержка индексов:

# 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']

Важно, какой источник DataStore используется

  • Источник DataFrame: сохраняет индекс pandas
  • Файловый источник: использует простой целочисленный индекс

7. Поведение при сравнении

Сравнение с pandas

pandas не распознаёт объекты типа 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())  # True

Использование метода equals()

# DataStore.equals() also works
dsf.equals(pdf)  # Compares with pandas DataFrame

8. Вывод типов

pandas

Используются типы numpy/pandas:

df['col'].dtype  # int64, float64, object, datetime64, etc.

DataStore

Может использовать типы данных 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 type

Явное приведение типов

# Force specific type
ds['col'] = ds['col'].astype('int64')

9. Модель памяти

pandas

Все данные хранятся в памяти:

df = pd.read_csv("huge.csv")  # 10GB in memory!

DataStore

Данные остаются в исходном источнике до тех пор, пока не понадобятся:

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 now

10. Сообщения об ошибках

Различные источники ошибок

  • ошибки pandas: из библиотеки pandas
  • ошибки DataStore: из chDB или ClickHouse
# May see ClickHouse-style errors
# "Code: 62. DB::Exception: Syntax error..."

Рекомендации по отладке

# 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()

Контрольный список миграции

При миграции с pandas:

  • Измените инструкцию import
  • Удалите параметры inplace=True
  • Добавьте явный вызов to_df(), когда требуется pandas DataFrame
  • Добавьте сортировку, если важен порядок строк
  • Используйте to_pandas() для сравнительных тестов
  • Тестируйте на репрезентативных объёмах данных

Краткая справка

pandasDataStore
df[condition]Аналогично (возвращает DataStore)
df.groupby()Аналогично (возвращает 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)Аналогично (запускает выполнение)
len(df)Аналогично (запускает выполнение)