互換性へのアプローチ
# 典型的な移行 - インポートを変更するだけ
- import pandas as pd
+ from chdb import datastore as pd
# コードはそのまま動作する
df = pd.read_csv("data.csv")
result = df[df['age'] > 25].groupby('city')['salary'].mean()
- pandas の 209 個の DataFrame メソッドをすべて実装
- SQL 最適化のための遅延評価
- 型の自動ラップ (DataFrame → DataStore、Series → ColumnExpr)
- イミュータブルな操作 (
inplace=Trueはなし)
属性とプロパティ
| プロパティ | 説明 | 実行をトリガーするか |
|---|---|---|
shape | (行数、カラム数) のタプル | はい |
columns | カラム名 (Index) | はい |
dtypes | カラムのデータ型 | はい |
values | NumPy配列 | はい |
index | 行インデックス | はい |
size | 要素数 | はい |
ndim | 次元数 | いいえ |
empty | DataFrame が空かどうか | はい |
T | 転置 | はい |
axes | 軸のリスト | はい |
from chdb import datastore as pd
ds = pd.read_csv("data.csv")
print(ds.shape) # (1000, 5)
print(ds.columns) # Index(['name', 'age', 'city', 'salary', 'dept'])
print(ds.dtypes) # name: object, age: int64, ...
print(ds.empty) # False
索引参照と選択
| 方法 | 説明 | 例 |
|---|---|---|
df['col'] | カラムを選択 | ds['age'] |
df[['col1', 'col2']] | 複数のカラムを選択 | ds[['name', 'age']] |
df[condition] | ブール索引 | ds[ds['age'] > 25] |
df.loc[...] | ラベルベースのアクセス | ds.loc[0:10, 'name'] |
df.iloc[...] | 整数位置ベースのアクセス | ds.iloc[0:10, 0:3] |
df.at[...] | ラベルで単一の値にアクセス | ds.at[0, 'name'] |
df.iat[...] | 位置で単一の値にアクセス | ds.iat[0, 0] |
df.head(n) | 先頭の n 行 | ds.head(10) |
df.tail(n) | 末尾の n 行 | ds.tail(10) |
df.sample(n) | ランダムサンプル | ds.sample(100) |
df.select_dtypes() | Dtype で選択 | ds.select_dtypes(include='number') |
df.query() | クエリ式 | ds.query('age > 25') |
df.where() | 条件に応じて置換 | ds.where(ds['age'] > 0, 0) |
df.mask() | where の逆 | ds.mask(ds['age'] < 0, 0) |
df.isin() | 値が含まれるか判定 | ds['city'].isin(['NYC', 'LA']) |
df.get() | 安全にカラムへアクセス | ds.get('col', default=None) |
df.xs() | 断面を取得 | ds.xs('key') |
df.pop() | カラムを削除 | ds.pop('col') |
統計メソッド
| メソッド | 説明 | 対応する SQL |
|---|---|---|
mean() | 平均値 | AVG() |
median() | 中央値 | MEDIAN() |
mode() | 最頻値 | - |
std() | 標準偏差 | STDDEV() |
var() | 分散 | VAR() |
min() | 最小値 | MIN() |
max() | 最大値 | MAX() |
sum() | 合計 | SUM() |
prod() | 積 | - |
count() | NULL 以外の数 | COUNT() |
nunique() | 一意な値の件数 | UNIQ() |
value_counts() | 値ごとの出現頻度 | GROUP BY |
quantile() | 分位数 | QUANTILE() |
describe() | 要約統計量 | - |
corr() | 相関行列 | CORR() |
cov() | 共分散行列 | COV() |
corrwith() | ペアごとの相関 | - |
rank() | 順位付け | RANK() |
abs() | 絶対値 | ABS() |
round() | 値の丸め | ROUND() |
clip() | 値を範囲に収める | - |
cumsum() | 累積和 | ウィンドウ関数 |
cumprod() | 累積積 | ウィンドウ関数 |
cummin() | 累積最小値 | ウィンドウ関数 |
cummax() | 累積最大値 | ウィンドウ関数 |
diff() | 差分 | ウィンドウ関数 |
pct_change() | 変化率 | ウィンドウ関数 |
skew() | 歪度 | SKEW() |
kurt() | 尖度 | KURT() |
sem() | 標準誤差 | - |
all() | すべてが true | - |
any() | いずれかが true | - |
idxmin() | 最小値の位置 | - |
idxmax() | 最大値の位置 | - |
ds = pd.read_csv("data.csv")
# 基本的な統計
print(ds['salary'].mean())
print(ds['age'].std())
print(ds.describe())
# グループ別統計
print(ds.groupby('department')['salary'].mean())
print(ds.groupby('city').agg({'salary': ['mean', 'std'], 'age': 'count'}))
データ操作
| メソッド | 説明 |
|---|---|
drop() | 行またはカラムを削除 |
drop_duplicates() | 重複を削除 |
duplicated() | 重複を示す |
dropna() | 欠損値を削除 |
fillna() | 欠損値を補完 |
ffill() | 前方補完 |
bfill() | 後方補完 |
interpolate() | 値を補間 |
replace() | 値を置換 |
rename() | カラム/索引名を変更 |
rename_axis() | 軸名を変更 |
assign() | 新しいカラムを追加 |
astype() | 型を変換 |
convert_dtypes() | 型を推論 |
copy() | DataFrameをコピー |
ds = pd.read_csv("data.csv")
# 削除操作
result = ds.drop(columns=['unused_col'])
result = ds.drop_duplicates(subset=['user_id'])
result = ds.dropna(subset=['email'])
# 補完操作
result = ds.fillna(0)
result = ds.fillna({'age': 0, 'name': 'Unknown'})
# 変換操作
result = ds.rename(columns={'old_name': 'new_name'})
result = ds.assign(
full_name=lambda x: x['first_name'] + ' ' + x['last_name'],
age_group=lambda x: pd.cut(x['age'], bins=[0, 25, 50, 100])
)
ソートとランキング
| Method | Description |
|---|---|
sort_values() | 値でソート |
sort_index() | 索引でソート |
nlargest() | 大きい値から N 件 |
nsmallest() | 小さい値から N 件 |
# 単一カラムでソート
result = ds.sort_values('salary', ascending=False)
# 複数カラムでソート
result = ds.sort_values(['department', 'salary'], ascending=[True, False])
# 上位/下位 N 件を取得
result = ds.nlargest(10, 'salary')
result = ds.nsmallest(5, 'age')
形状変更
| Method | Description |
|---|---|
pivot() | ピボットテーブル |
pivot_table() | 集約付きピボット |
melt() | アンピボット |
stack() | カラムを索引に積み重ねる |
unstack() | 索引をカラムに展開する |
transpose() / T | 転置 |
explode() | リストを行に展開する |
squeeze() | 次元を削減する |
droplevel() | 索引レベルを削除する |
swaplevel() | 索引レベルを入れ替える |
reorder_levels() | レベルを並べ替える |
# ピボットテーブル
result = ds.pivot_table(
values='amount',
index='region',
columns='product',
aggfunc='sum'
)
# メルト(アンピボット)
result = ds.melt(
id_vars=['name'],
value_vars=['score1', 'score2', 'score3'],
var_name='test',
value_name='score'
)
# 配列の展開
result = ds.explode('tags')
結合 / JOIN
| Method | Description |
|---|---|
merge() | SQL 形式のマージ |
join() | 索引で結合 |
concat() | 連結 |
append() | 行を追加 |
combine() | 関数で結合 |
combine_first() | 優先順位に従って結合 |
update() | 値を更新 |
compare() | 差分を表示 |
# マージ(結合)
result = pd.merge(df1, df2, on='id', how='left')
result = df1.join(df2, on='id')
# 連結
result = pd.concat([df1, df2, df3])
result = pd.concat([df1, df2], axis=1)
二項演算
| メソッド | 説明 |
|---|---|
add() / radd() | 加算 |
sub() / rsub() | 減算 |
mul() / rmul() | 乗算 |
div() / rdiv() | 除算 |
truediv() / rtruediv() | 真の除算 |
floordiv() / rfloordiv() | 切り捨て除算 |
mod() / rmod() | 剰余 |
pow() / rpow() | べき乗 |
dot() | 行列積 |
# 算術演算
result = ds['col1'].add(ds['col2'])
result = ds['price'].mul(ds['quantity'])
# 欠損データにfill_valueを使用する場合
result = ds['col1'].add(ds['col2'], fill_value=0)
比較演算
| メソッド | 説明 |
|---|---|
eq() | 等しい |
ne() | 等しくない |
lt() | 未満 |
le() | 以下 |
gt() | より大きい |
ge() | 以上 |
equals() | 等価性を確認する |
compare() | 差異を表示する |
関数の適用
| メソッド | 説明 |
|---|---|
apply() | 関数を適用 |
applymap() | 要素ごとに適用 |
map() | 値をマッピング |
agg() / aggregate() | 集約 |
transform() | 変換 |
pipe() | 関数をパイプで連結 |
groupby() | グループ化 |
# 関数を適用
result = ds['name'].apply(lambda x: x.upper())
result = ds.apply(lambda row: row['a'] + row['b'], axis=1)
# 集計
result = ds.agg({'col1': 'sum', 'col2': 'mean'})
result = ds.agg(['sum', 'mean', 'std'])
# パイプ
result = (ds
.pipe(filter_active)
.pipe(calculate_metrics)
.pipe(format_output)
)
時系列
| Method | Description |
|---|---|
rolling() | ローリングウィンドウ |
expanding() | 累積ウィンドウ |
ewm() | 指数加重 |
resample() | 時系列を再サンプリング |
shift() | 値をシフト |
asfreq() | 頻度を変換 |
asof() | その時点での最新の値 |
at_time() | 指定時刻のデータを選択 |
between_time() | 時刻範囲を選択 |
first() / last() | 先頭/末尾の期間 |
to_period() | periodに変換 |
to_timestamp() | タイムスタンプに変換 |
tz_convert() | タイムゾーンを変換 |
tz_localize() | タイムゾーンを設定 |
# ローリングウィンドウ
result = ds['value'].rolling(window=7).mean()
# 拡張ウィンドウ
result = ds['value'].expanding().sum()
# シフト
result = ds['value'].shift(1) # ラグ
result = ds['value'].shift(-1) # リード
欠損値
| メソッド | 説明 |
|---|---|
isna() / isnull() | 欠損値を検出 |
notna() / notnull() | 非欠損値を検出 |
dropna() | 欠損値を削除 |
fillna() | 欠損値を補完 |
ffill() | 前方補完 |
bfill() | 後方補完 |
interpolate() | 補間 |
replace() | 値を置換 |
I/O メソッド
| メソッド | 説明 |
|---|---|
to_csv() | CSV にエクスポート |
to_json() | JSON にエクスポート |
to_excel() | Excel にエクスポート |
to_parquet() | Parquet にエクスポート |
to_feather() | Feather にエクスポート |
to_sql() | SQL データベースにエクスポート |
to_pickle() | Pickle |
to_html() | HTML テーブル |
to_latex() | LaTeX テーブル |
to_markdown() | Markdown テーブル |
to_string() | 文字列表現 |
to_dict() | Dictionary |
to_records() | レコード |
to_numpy() | NumPy 配列 |
to_clipboard() | クリップボード |
イテレーション
| メソッド | 説明 |
|---|---|
items() | (カラム, Series) を反復 |
iterrows() | (索引, Series) を反復 |
itertuples() | 名前付きタプルとして反復 |
Pandasとの主な違い
1. 戻り値の型
# Pandas は Series を返す
pdf['col'] # → pd.Series
# DataStore は(遅延評価の)ColumnExpr を返す
ds['col'] # → ColumnExpr
2. 遅延実行
# DataStore の操作は遅延評価されます
result = ds.filter(ds['age'] > 25) # この時点ではまだ実行されません
df = result.to_df() # ここで実行されます
3. inplace パラメータはない
# Pandas
df.drop(columns=['col'], inplace=True)
# DataStore(常に新しいオブジェクトを返す)
ds = ds.drop(columns=['col'])
4. 結果を比較する
# 比較には to_pandas() を使用します
pd.testing.assert_frame_equal(
ds.to_pandas(),
expected_df
)