> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-fbfa8bee.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 与 pandas 的关键差异

> DataStore 与 pandas 之间的重要差异

虽然 DataStore 与 pandas 高度兼容，但仍有一些需要了解的重要差异。

<div id="summary">
  ## 总结表
</div>

| 项目          | pandas           | DataStore                                                                |
| ----------- | ---------------- | ------------------------------------------------------------------------ |
| **执行**      | 立即 (即时)          | 惰性 (延迟)                                                                  |
| **返回类型**    | DataFrame/Series | DataStore/ColumnExpr                                                     |
| **行顺序**     | 保持不变             | 保持不变 (自动) ；在[性能模式](/zh/products/chdb/configuration/performance-mode)下不保证 |
| **inplace** | 支持               | 不支持                                                                      |
| **索引**      | 完整支持             | 简化                                                                       |
| **内存**      | 所有数据均在内存中        | 数据保留在源端                                                                  |

***

<div id="lazy-execution">
  ## 1. 惰性执行 vs 立即执行
</div>

<div id="pandas-eager">
  ### pandas (立即执行)
</div>

操作会立即执行：

```python theme={null}
import pandas as pd

df = pd.read_csv("data.csv")  # 立即加载整个文件
result = df[df['age'] > 25]   # 立即过滤
grouped = result.groupby('city')['salary'].mean()  # 立即聚合
```

<div id="datastore-lazy">
  ### DataStore (惰性)
</div>

操作会延迟到需要结果时才执行：

```python theme={null}
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 时触发执行
```

<div id="why-lazy">
  ### 为什么这很重要
</div>

惰性执行带来：

* **查询优化**：多个操作可合并编译为一条 SQL 查询
* **列裁剪**：只读取所需的列
* **过滤器下推**：过滤器可在数据源端生效
* **内存效率**：无需加载不需要的数据

***

<div id="return-types">
  ## 2. 返回类型
</div>

<div id="pandas-return-types">
  ### pandas
</div>

```python theme={null}
df['col']           # 返回 pd.Series
df[['a', 'b']]      # 返回 pd.DataFrame
df[df['x'] > 10]    # 返回 pd.DataFrame
df.groupby('x')     # 返回 DataFrameGroupBy
```

<div id="datastore-return-types">
  ### DataStore
</div>

```python theme={null}
ds['col']           # 返回 ColumnExpr（惰性）
ds[['a', 'b']]      # 返回 DataStore（惰性）
ds[ds['x'] > 10]    # 返回 DataStore（惰性）
ds.groupby('x')     # 返回 LazyGroupBy
```

<div id="converting-to-pandas-types">
  ### 转换为 pandas 数据类型
</div>

```python theme={null}
# 获取 pandas DataFrame
df = ds.to_df()
df = ds.to_pandas()

# 从列中获取 pandas Series
series = ds['col'].to_pandas()

# 或触发执行
print(ds)  # 自动转换以供显示
```

***

<div id="triggers">
  ## 3. 执行触发条件
</div>

DataStore 会在需要实际值时执行：

| Trigger              | Example            | Notes   |
| -------------------- | ------------------ | ------- |
| `print()` / `repr()` | `print(ds)`        | 显示时需要数据 |
| `len()`              | `len(ds)`          | 需要行数    |
| `.columns`           | `ds.columns`       | 需要列名    |
| `.dtypes`            | `ds.dtypes`        | 需要类型信息  |
| `.shape`             | `ds.shape`         | 需要维度信息  |
| `.values`            | `ds.values`        | 需要实际数据  |
| `.index`             | `ds.index`         | 需要索引    |
| `to_df()`            | `ds.to_df()`       | 显式转换    |
| Iteration            | `for row in ds`    | 需要进行迭代  |
| `equals()`           | `ds.equals(other)` | 需要比较    |

<div id="stay-lazy">
  ### 保持惰性执行的操作
</div>

| 操作               | 返回值         |
| ---------------- | ----------- |
| `filter()`       | DataStore   |
| `select()`       | DataStore   |
| `sort()`         | DataStore   |
| `groupby()`      | LazyGroupBy |
| `join()`         | DataStore   |
| `ds['col']`      | ColumnExpr  |
| `ds[['a', 'b']]` | DataStore   |
| `ds[condition]`  | DataStore   |

***

<div id="row-order">
  ## 4. 行顺序
</div>

<div id="pandas-return-types">
  ### pandas
</div>

行顺序始终保持不变：

```python theme={null}
df = pd.read_csv("data.csv")
print(df.head())  # 始终与文件中的顺序相同
```

<div id="datastore-return-types">
  ### DataStore
</div>

在大多数操作中，**行顺序都会自动保留**：

```python theme={null}
ds = pd.read_csv("data.csv")
print(ds.head())  # 与文件顺序一致

# 过滤后顺序保持不变
ds_filtered = ds[ds['age'] > 25]  # 与 pandas 顺序相同
```

DataStore 会自动在内部跟踪原始行位置 (使用 `rowNumberInAllBlocks()`) ，以确保顺序与 pandas 一致。

<div id="order-preserved">
  ### 保留顺序的情况
</div>

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

<div id="order-may-differ">
  ### 顺序可能不同的情况
</div>

* 在 `groupby()` 聚合之后 (使用 `sort_values()` 以确保顺序一致)
* 在使用某些 join 类型进行 `merge()` / `join()` 之后
* 在 **性能模式** (`config.use_performance_mode()`) 下：任何操作的行顺序都不作保证。请参见 [Performance Mode](/zh/products/chdb/configuration/performance-mode)。

***

<div id="no-inplace">
  ## 5. 不支持 inplace 参数
</div>

<div id="pandas-return-types">
  ### pandas
</div>

```python theme={null}
df.drop(columns=['col'], inplace=True)  # 修改 df
df.fillna(0, inplace=True)              # 修改 df
df.rename(columns={'old': 'new'}, inplace=True)
```

<div id="datastore-return-types">
  ### DataStore
</div>

不支持 `inplace=True`。请始终将结果赋值给变量：

```python theme={null}
ds = ds.drop(columns=['col'])           # 返回新的 DataStore
ds = ds.fillna(0)                       # 返回新的 DataStore
ds = ds.rename(columns={'old': 'new'})  # 返回新的 DataStore
```

<div id="why-no-inplace">
  ### 为什么不支持 inplace？
</div>

DataStore 使用不可变操作，以支持：

* 查询构建 (惰性求值)
* 线程安全
* 更方便调试
* 更简洁的代码

***

<div id="index">
  ## 6. 索引支持
</div>

<div id="pandas-return-types">
  ### pandas
</div>

全面支持索引：

```python theme={null}
df = df.set_index('id')
df.loc['user123']           # 基于标签的访问
df.loc['a':'z']             # 基于标签的切片
df.reset_index()
df.index.name = 'user_id'
```

<div id="datastore-return-types">
  ### DataStore
</div>

简化的索引支持：

```python theme={null}
# 基本操作可正常使用
ds.loc[0:10]               # 整数位置
ds.iloc[0:10]              # 与 DataStore 的 loc 相同

# 如需使用 pandas 风格的索引操作，请先进行转换
df = ds.to_df()
df = df.set_index('id')
df.loc['user123']
```

<div id="datastore-source-matters">
  ### DataStore 来源很关键
</div>

* **DataFrame 来源**：保留 pandas 索引
* **文件来源**：使用简单的整数索引

***

<div id="comparison">
  ## 7. 比较行为
</div>

<div id="comparing-with-pandas">
  ### 与 pandas 的比较
</div>

pandas 无法识别 DataStore 对象：

```python theme={null}
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
```

<div id="using-equals">
  ### 使用 equals()
</div>

```python theme={null}
# DataStore.equals() 也可用
dsf.equals(pdf)  # 与 pandas DataFrame 进行比较
```

***

<div id="types">
  ## 8. 类型推断
</div>

<div id="pandas-return-types">
  ### pandas
</div>

使用 numpy/pandas 类型：

```python theme={null}
df['col'].dtype  # int64, float64, object, datetime64 等
```

<div id="datastore-return-types">
  ### DataStore
</div>

可使用 ClickHouse 类型：

```python theme={null}
ds['col'].dtype  # Int64、Float64、String、DateTime 等

# 转为 pandas 时，类型也会随之转换
df = ds.to_df()
df['col'].dtype  # 现为 pandas 类型
```

<div id="explicit-casting">
  ### 显式类型转换
</div>

```python theme={null}
# 强制指定类型
ds['col'] = ds['col'].astype('int64')
```

***

<div id="memory">
  ## 9. 内存模型
</div>

<div id="pandas-return-types">
  ### pandas
</div>

所有数据都存储在内存中：

```python theme={null}
df = pd.read_csv("huge.csv")  # 10GB 占用内存！
```

<div id="datastore-return-types">
  ### DataStore
</div>

数据保留在源端，按需使用：

```python theme={null}
ds = pd.read_csv("huge.csv")  # 仅元数据
ds = ds.filter(ds['year'] == 2024)  # 仍仅为元数据

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

***

<div id="errors">
  ## 10. 错误信息
</div>

<div id="different-error-sources">
  ### 不同的错误来源
</div>

* **pandas 错误**：来自 pandas 库
* **DataStore 错误**：来自 chDB 或 ClickHouse

```python theme={null}
# 可能会看到 ClickHouse 风格的错误
# "Code: 62. DB::Exception: Syntax error..."
```

<div id="debugging-tips">
  ### 调试技巧
</div>

```python theme={null}
# 查看 SQL 以进行调试
print(ds.to_sql())

# 查看执行计划
ds.explain()

# 启用调试日志
from chdb.datastore.config import config
config.enable_debug()
```

***

<div id="checklist">
  ## 迁移清单
</div>

从 pandas 迁移时：

* [ ] 修改 import 语句
* [ ] 移除 `inplace=True` 参数
* [ ] 在需要 pandas DataFrame 的地方显式调用 `to_df()`
* [ ] 如果行顺序很重要，请添加排序
* [ ] 使用 `to_pandas()` 进行对比测试
* [ ] 使用具有代表性的数据规模进行测试

***

<div id="quick-ref">
  ## 快速参考
</div>

| pandas                  | DataStore                      |
| ----------------------- | ------------------------------ |
| `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)`               | 相同 (会触发执行)                     |
