欠損データ(Missing data)
このページでは、Polars における欠損データの表現方法と、欠損データの補完方法について説明します。
null
と NaN
値
DataFrame
(または同等の Series
)の各カラムは、Arrow 配列または Arrow 配列の集合です(Apache Arrow 形式に基づいています)。欠損データは、Arrow および Polars で null
値として表されます。この null
値は、数値を含むすべてのデータタイプに適用されます。
Polars は、浮動小数点カラムに対して NotaNumber
または NaN
値を許容しています。これらの NaN
値は、欠損データではなく浮動小数点データの一種と見なされます。NaN
値については後述します。
Python の None
値を使用して、手動で欠損値を定義することができます:
shape: (2, 1)
┌───────┐
│ value │
│ --- │
│ i64 │
╞═══════╡
│ 1 │
│ null │
└───────┘
Info
pandas では、カラムの dtype によって欠損データの値が異なります。Polars では、欠損データは常に null
値として表されます。
欠損データのメタデータ
Polars で使用される各 Arrow 配列は、欠損データに関連する二種類のメタデータを格納しています。このメタデータにより、Polars は欠損値の数とどの値が欠損しているかを迅速に示すことができます。
最初のメタデータは null_count
で、これはカラム内の null
値を持つ行の数です:
null_count_df = df.null_count()
print(null_count_df)
let null_count_df = df.null_count();
println!("{}", &null_count_df);
shape: (1, 1)
┌───────┐
│ value │
│ --- │
│ u32 │
╞═══════╡
│ 1 │
└───────┘
null_count
メソッドは DataFrame
、DataFrame
のカラム、または Series
に対して呼び出すことができます。null_count
メソッドは、基本的な Arrow 配列で null_count
がすでに計算されているため、低コストの操作です。
もう一つのメタデータは、各データ値が有効か欠損かを示す validity bitmap と呼ばれる配列です。
validity bitmap はメモリ効率が良いです。なぜなら、ビットエンコードされているからです(各値は 0 または 1)。このビットエンコードにより、配列ごとのメモリオーバーヘッドは(配列の長さ / 8)バイトのみです。validity bitmap は Polars の is_null
メソッドで使用されます。
DataFrame
または Series
のカラムに対する validity bitmap を基に Series
を返すことが、is_null
メソッドで可能です:
shape: (2, 1)
┌───────┐
│ value │
│ --- │
│ bool │
╞═══════╡
│ false │
│ true │
└───────┘
is_null
メソッドは、null
値を完全にスキャンする必要がないため、低コストの操作です。これは、validity bitmap がすでに存在し、Boolean 配列として返されるためです。
欠損データの補完
Series
の欠損データは、fill_null
メソッドで補完することができます。欠損データをどのように補完するかを指定する必要があります。これを行う主な方法は次のとおりです:
- リテラル(0 や "0" など)で補完
- 戦略(前方に補完するなど)で補完
- 別のカラムからの値で置換するなどのエクスプレッションで補完
- 補間
欠損値がある col2
を持つシンプルな DataFrame
を定義して、null を補完する方法を示します:
shape: (3, 2)
┌──────┬──────┐
│ col1 ┆ col2 │
│ --- ┆ --- │
│ i64 ┆ i64 │
╞══════╪══════╡
│ 1 ┆ 1 │
│ 2 ┆ null │
│ 3 ┆ 3 │
└──────┴──────┘
指定されたリテラル値で補完
指定されたリテラル値で欠損データを補完することができます。例えば pl.lit
を使います:
shape: (3, 2)
┌──────┬──────┐
│ col1 ┆ col2 │
│ --- ┆ --- │
│ i64 ┆ i64 │
╞══════╪══════╡
│ 1 ┆ 1 │
│ 2 ┆ 2 │
│ 3 ┆ 3 │
└──────┴──────┘
戦略で補完
欠損データを戦略で補完することができます。例えば、前方に補完する戦略です:
shape: (3, 2)
┌──────┬──────┐
│ col1 ┆ col2 │
│ --- ┆ --- │
│ i64 ┆ i64 │
╞══════╪══════╡
│ 1 ┆ 1 │
│ 2 ┆ 1 │
│ 3 ┆ 3 │
└──────┴──────┘
API ドキュメントで他の補完戦略を見つけることができます。
エクスプレッションで補完
より柔軟性を持って欠損データを補完することができます。 例えば、そのカラムの中央値で null を補完します:
shape: (3, 2)
┌──────┬──────┐
│ col1 ┆ col2 │
│ --- ┆ --- │
│ i64 ┆ f64 │
╞══════╪══════╡
│ 1 ┆ 1.0 │
│ 2 ┆ 2.0 │
│ 3 ┆ 3.0 │
└──────┴──────┘
この場合、中央値が浮動小数点統計であるため、カラムは整数から浮動小数点にキャストされます。
補間で補完
さらに、補間を使用して(fill_null
関数を使用せずに)null を補完することもできます:
fill_interpolation_df = df.with_columns(
pl.col("col2").interpolate(),
)
print(fill_interpolation_df)
let fill_interpolation_df = df
.clone()
.lazy()
.with_columns([col("col2").interpolate(InterpolationMethod::Linear)])
.collect()?;
println!("{}", &fill_interpolation_df);
shape: (3, 2)
┌──────┬──────┐
│ col1 ┆ col2 │
│ --- ┆ --- │
│ i64 ┆ f64 │
╞══════╪══════╡
│ 1 ┆ 1.0 │
│ 2 ┆ 2.0 │
│ 3 ┆ 3.0 │
└──────┴──────┘
NotaNumber
または NaN
値
Series
の欠損データには null
値があります。しかし、浮動小数点データ型のカラムでは NotaNumber
または NaN
値を使用することができます。これらの NaN
値は、Numpy の np.nan
またはネイティブ Python の float('nan')
から作成することができます:
shape: (4, 1)
┌───────┐
│ value │
│ --- │
│ f64 │
╞═══════╡
│ 1.0 │
│ NaN │
│ NaN │
│ 3.0 │
└───────┘
Info
pandas では、整数カラムの NaN
値がデフォルトでカラムを浮動小数点にキャストします。これは Polars では起こらず、代わりに例外が発生します。
NaN
値は浮動小数点データの一種と見なされ、Polars では欠損データとは見なされません。つまり:
NaN
値はnull_count
メソッドでカウントされませんNaN
値はfill_nan
メソッドで補完されますが、fill_null
メソッドでは補完されません
Polars には is_nan
と fill_nan
のメソッドがあり、is_null
と fill_null
のメソッドと同様に動作します。NaN
値には事前計算された validity bitmap がないため、is_nan
メソッド用にこれを計算する必要があります。
null
と NaN
値のもう一つの違いは、null
値を含むカラムの平均を取る場合、null
値は計算から除外されますが、NaN
値を含む場合、平均を取ると NaN
になります。この挙動は、NaN
値を null
値に置き換えることで回避することができます:
shape: (1, 1)
┌───────┐
│ value │
│ --- │
│ f64 │
╞═══════╡
│ 2.0 │
└───────┘