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

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

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

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

pandas (Немедленное выполнение)

Операции выполняются сразу:
import pandas as pd

df = pd.read_csv("data.csv")  # Загружает весь файл СЕЙЧАС
result = df[df['age'] > 25]   # Фильтрует СЕЙЧАС
grouped = result.groupby('city')['salary'].mean()  # Агрегирует СЕЙЧАС

DataStore (ленивое выполнение)

Операции выполняются только тогда, когда нужны результаты:
from chdb import datastore as pd

ds = pd.read_csv("data.csv")  # Только фиксирует источник
result = ds[ds['age'] > 25]   # Только фиксирует фильтр
grouped = result.groupby('city')['salary'].mean()  # Только фиксирует

# Выполнение происходит здесь:
print(grouped)        # Выполняется при выводе
df = grouped.to_df()  # Или при преобразовании в pandas

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

Ленивое выполнение позволяет:
  • Оптимизация запросов: Несколько операций компилируются в один SQL-запрос
  • Отсечение столбцов: Считываются только нужные столбцы
  • Pushdown фильтров: Фильтры применяются на стороне источника
  • Эффективное использование памяти: Не загружайте данные, которые не нужны

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

pandas

df['col']           # Возвращает pd.Series
df[['a', 'b']]      # Возвращает pd.DataFrame
df[df['x'] > 10]    # Возвращает pd.DataFrame
df.groupby('x')     # Возвращает DataFrameGroupBy

DataStore

ds['col']           # Возвращает ColumnExpr (с ленивым вычислением)
ds[['a', 'b']]      # Возвращает DataStore (с ленивым вычислением)
ds[ds['x'] > 10]    # Возвращает DataStore (с ленивым вычислением)
ds.groupby('x')     # Возвращает LazyGroupBy

Преобразование в типы pandas

# Получить pandas DataFrame
df = ds.to_df()
df = ds.to_pandas()

# Получить pandas Series из столбца
series = ds['col'].to_pandas()

# Или инициировать выполнение
print(ds)  # Автоматически преобразует для отображения

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())  # Всегда в том же порядке, что и в файле

DataStore

При большинстве операций порядок строк сохраняется автоматически:
ds = pd.read_csv("data.csv")
print(ds.head())  # Соответствует порядку в файле

# Фильтр сохраняет порядок
ds_filtered = ds[ds['age'] > 25]  # Тот же порядок, что и в pandas
DataStore автоматически отслеживает исходные позиции строк (с помощью rowNumberInAllBlocks()), чтобы сохранять порядок, согласованный с pandas.

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

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

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

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

5. Параметр inplace отсутствует

pandas

df.drop(columns=['col'], inplace=True)  # Изменяет df
df.fillna(0, inplace=True)              # Изменяет df
df.rename(columns={'old': 'new'}, inplace=True)

DataStore

Параметр inplace=True не поддерживается. Всегда присваивайте результат:
ds = ds.drop(columns=['col'])           # Возвращает новый DataStore
ds = ds.fillna(0)                       # Возвращает новый DataStore
ds = ds.rename(columns={'old': 'new'})  # Возвращает новый DataStore

Почему нет inplace?

DataStore использует неизменяемые операции, что позволяет:
  • Строить запросы (отложенное вычисление)
  • Обеспечивать потокобезопасность
  • Упрощать отладку
  • Делать код чище

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

pandas

Полная поддержка индексов:
df = df.set_index('id')
df.loc['user123']           # Доступ по метке
df.loc['a':'z']             # Срез по меткам
df.reset_index()
df.index.name = 'user_id'

DataStore

Упрощённая поддержка индексов:
# Базовые операции работают
ds.loc[0:10]               # Позиция по целому числу
ds.iloc[0:10]              # Аналогично loc для DataStore

# Для операций с индексами в стиле pandas сначала выполните преобразование
df = ds.to_df()
df = df.set_index('id')
df.loc['user123']

Имеет значение источник DataStore

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

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]})

# Это работает не так, как ожидается
pdf == dsf  # pandas не знает о DataStore

# Решение: преобразовать DataStore в pandas
pdf.equals(dsf.to_pandas())  # True

Использование функции equals()

# DataStore.equals() тоже работает
dsf.equals(pdf)  # Сравнивает с DataFrame из pandas

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

pandas

Используются типы numpy/pandas:
df['col'].dtype  # int64, float64, object, datetime64, и т.д.

DataStore

Можно использовать типы ClickHouse:
ds['col'].dtype  # Int64, Float64, String, DateTime и т. д.

# При переходе в pandas типы преобразуются
df = ds.to_df()
df['col'].dtype  # Теперь тип данных pandas

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

# Принудительное приведение к конкретному типу
ds['col'] = ds['col'].astype('int64')

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

pandas

Все данные хранятся в памяти:
df = pd.read_csv("huge.csv")  # 10 ГБ в памяти!

DataStore

Данные остаются в источнике, пока не потребуются:
ds = pd.read_csv("huge.csv")  # Только метаданные
ds = ds.filter(ds['year'] == 2024)  # По-прежнему только метаданные

# Загружается только отфильтрованный результат
df = ds.to_df()  # Теперь, возможно, всего 1 ГБ

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

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

  • ошибки pandas: Из библиотеки pandas
  • ошибки DataStore: Из chDB или ClickHouse
# Возможны ошибки в стиле ClickHouse
# "Code: 62. DB::Exception: Syntax error..."

Советы по отладке

# Просмотр SQL для отладки
print(ds.to_sql())

# Просмотр плана выполнения
ds.explain()

# Включить отладочное логирование
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)То же (инициирует выполнение)
Последнее изменение 10 июня 2026 г.