これは matten を紹介する全 4 回シリーズの第 3 回です。前回は数値計算のコア部分を紹介しました。今回は雑然とした実世界のデータを取り込むしくみについてです。
課題事項
前回紹介した Tensor (数値テンソル)は、つくられた時点からクリーンです。すべてのセルが f64 です。データがすでにクリーンであれば、それで問題ありません。しかし、データが JSON API や CSV ファイル経由で投入され、その中に欠損セルや、整数と浮動小数点の混在、あるいは bool 値(フラグ)が含まれているような場合となると、どうでしょうか。話は変わって来ます。
dynamic feature は、そのような場合の助けになります。データ取り込みとクリーニングのレイヤーを追加します。ただし、これは第二の計算エンジンではありません — dynamic テンソルで直接算術演算はできません。考え方はもっとシンプルです。不均一なデータを取り込み、検査してクリーニングし、データが整ったと確信したら数値テンソルに明示的に変換します。
次のようにして有効化できます:
matten = { version = "0.28", features = ["dynamic"] }
混在データの取り込み
from_json_dynamic と from_csv_dynamic は、型が混在したデータを受け付けます。各セルは Element のバリアントに格納されます:Float、Int、Bool、Text、または None(JSON の null や CSV の空フィールド)。
use matten::{NumericPolicy, Tensor};
// 数値の種類が混在し、かつ欠損セルが存在する JSON テーブル
let json = "[[1, 2.5, null], [4.0, 5, 6]]";
let t = Tensor::from_json_dynamic(json)?;
assert!(t.is_dynamic());
assert_eq!(t.shape(), &[2, 3]);
assert_eq!(t.count_none(), 1);
同様の処理は CSV でも動きます:
use matten::Tensor;
let csv = "10.0,20.0,30.0\n40.0,,60.0\n70.0,80.0,\n"; // 空セルが 2 つ
let t = Tensor::from_csv_dynamic(csv)?;
assert_eq!(t.count_none(), 2);
フォーマットが異なるだけで、ワークフローは同じです。
欠損値の検査
クリーニングの前に、どこに欠損があるか確認できます:
// none_mask: セルごとに 0.0 / 1.0 の数値テンソル
let mask = t.none_mask();
assert_eq!(mask.get(&[0, 2]), Some(1.0)); // [0,2] に null
assert_eq!(mask.get(&[0, 0]), Some(0.0)); // 値あり
// schema_summary で型の内訳を読みやすく確認
println!("{}", t.schema_summary());
// 例: "Float: 4, Int: 1, None: 1"
数値テンソルへの変換
変換ステップは意図的に明示的にしています。try_numeric() は厳格です。None、Bool、Text が 1 つでもあれば変換を拒否します:
// データに null があるため失敗する
assert!(t.try_numeric().is_err());
try_numeric_with(policy) を使うと、各バリアントをどう扱うかを指定できます:
use matten::NumericPolicy;
// None を 0.0 として扱い、Int と Float はそのまま f64 に
let clean = t.try_numeric_with(NumericPolicy::default().none_as(0.0))?;
assert!(!clean.is_dynamic());
assert_eq!(clean.as_slice(), &[1.0, 2.5, 0.0, 4.0, 5.0, 6.0]);
その他の指定オプション:
// none_as_nan: 欠損を指定した値ではなく f64::NAN に
let p = NumericPolicy::default().none_as_nan();
// allow_bool: true → 1.0, false → 0.0
let p = NumericPolicy::default().allow_bool();
// allow_text_parse: テキストセルを f64 としてパースを試みる
let p = NumericPolicy::default().allow_text_parse();
// オプションを組み合わせる
let p = NumericPolicy::default().none_as(0.0).allow_bool();
// すべてのバリアントを受け入れる
let p = NumericPolicy::permissive();
変換前のクリーニング
変換ステップの前に欠損値を埋めることもできます:
// None をすべて 0.0 で埋める
let filled = t.fill_none(0.0);
assert!(filled.is_numeric_convertible());
// そのあと厳格に変換
let numeric = filled.try_numeric()?;
時系列データ向けに forward_fill_none(前の値で補完)も使えます。
dynamic でできないこと
dynamic feature には意図的に含まれていないものがあります:
- dynamic テンソルでの算術演算は不可。事前に
try_numeric()を実行してください。 - dynamic テンソルの reshape、slice、reduction は不可。
- dynamic テンソルの serde シリアライズは不可。
狙いは、きれいな受け渡しです。雑然とした入力 → 検査とクリーニング → 数値 Tensor → 通常の数値計算。この境界は意図的なものです。
Top comments (0)