跳转到主要内容
虽然 DataStore 与 pandas 高度兼容,但仍有一些需要了解的重要差异。

总结表

项目pandasDataStore
执行立即 (即时)惰性 (延迟)
返回类型DataFrame/SeriesDataStore/ColumnExpr
行顺序保持不变保持不变 (自动) ;在性能模式下不保证
inplace支持不支持
索引完整支持简化
内存所有数据均在内存中数据保留在源端

1. 惰性执行 vs 立即执行

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 查询
  • 列裁剪:只读取所需的列
  • 过滤器下推:过滤器可在数据源端生效
  • 内存效率:无需加载不需要的数据

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 会在需要实际值时执行:
TriggerExampleNotes
print() / repr()print(ds)显示时需要数据
len()len(ds)需要行数
.columnsds.columns需要列名
.dtypesds.dtypes需要类型信息
.shapeds.shape需要维度信息
.valuesds.values需要实际数据
.indexds.index需要索引
to_df()ds.to_df()显式转换
Iterationfor 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 一致。

保留顺序的情况

  • File 源 (CSV、Parquet、JSON 等)
  • pandas DataFrame 源
  • 过滤操作
  • 列选择
  • 显式调用 sort()sort_values() 之后
  • 会定义顺序的操作 (nlargest()nsmallest()head()tail())

顺序可能不同的情况

  • groupby() 聚合之后 (使用 sort_values() 以确保顺序一致)
  • 在使用某些 join 类型进行 merge() / join() 之后
  • 性能模式 (config.use_performance_mode()) 下:任何操作的行顺序都不作保证。请参见 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]              # 与 DataStore 的 loc 相同

# 如需使用 pandas 风格的索引操作,请先进行转换
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]})

# 这不会按预期工作
pdf == dsf  # pandas 无法识别 DataStore

# 解决方案:将 DataStore 转换为 pandas
pdf.equals(dsf.to_pandas())  # True

使用 equals()

# DataStore.equals() 也可用
dsf.equals(pdf)  # 与 pandas DataFrame 进行比较

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")  # 10GB 占用内存!

DataStore

数据保留在源端,按需使用:
ds = pd.read_csv("huge.csv")  # 仅元数据
ds = ds.filter(ds['year'] == 2024)  # 仍仅为元数据

# 仅加载过滤后的结果
df = ds.to_df()  # 现在可能只有 1GB

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 参数
  • 在需要 pandas DataFrame 的地方显式调用 to_df()
  • 如果行顺序很重要,请添加排序
  • 使用 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)相同 (会触发执行)
最后修改于 2026年6月10日