【VBAリファレンス】Power Queryで列数不定のCSVを自在に操る!M言語を活用した堅牢なデータ取り込み術

スポンサーリンク

概要:データ分析の現場で頻発する「列数不定」という悪夢

Excel VBAやPower Queryを用いたデータ統合業務において、最も頭を悩ませる問題の一つが「列数が一定ではないCSVファイル」の取り込みです。システムから自動生成されるログデータや、外部ベンダーから提供されるCSVファイルは、仕様変更や抽出条件の差異によって、ある日突然列が増減することがあります。

従来のVBAであれば、`Open`ステートメントでファイルを読み込み、`Split`関数でカンマ区切りに分解し、動的配列を再定義する……といった泥臭い処理が必要でした。しかし、Power Query(M言語)を習得すれば、このプロセスは劇的に簡略化されます。本記事では、列数が不定であってもエラーを吐かずにデータを統合するための、M言語による高度な動的処理技術を詳細に解説します。

詳細解説:列数不定を解決するためのロジックとM言語の核心

Power Queryの標準インターフェースでCSVを読み込む際、多くの場合 `Csv.Document` 関数が使用されます。しかし、この関数はデフォルトで列数を固定(`columns`引数)しようとします。これが列数不定のデータを取り込む際のエラーの主因です。

この問題を解決するための核心的なアプローチは「列数を明示的に指定せず、動的に検出させる」ことにあります。

M言語におけるデータ取り込みのフローは以下のステップで構成されます。

1. バイナリデータとしてソースを読み込む。
2. テキストとして変換し、各行を改行コードで分割する。
3. 各行をカンマで分割するが、この際、各行の最大要素数を動的に判定する。
4. 最大列数に合わせてダミーのヘッダーを生成し、全行を均一な構造に変換する。

特に重要なのが、`Table.FromList` 関数と `Splitter.SplitTextByDelimiter` 関数の組み合わせです。これらを活用することで、行ごとに異なる列数を持つCSVを、最大の列数に合わせてNULL補完し、フラットなテーブルに再構築することが可能となります。

サンプルコード:動的CSV読み込みの実装

以下に、列数が不明なCSVを読み込み、自動的に構造化するためのM言語コードを提示します。このコードは「詳細エディタ」に貼り付けて利用してください。


let
    // 1. CSVファイルをバイナリとして取得
    Source = File.Contents("C:\Data\UnstableColumns.csv"),
    
    // 2. テキストとして読み込み、行ごとに分割
    Lines = Table.FromColumns({Lines.FromBinary(Source)}),
    
    // 3. 各行をカンマで分割し、リスト化する
    SplitLines = Table.TransformColumns(Lines, {{"Column1", each Text.Split(_, ",")}}),
    
    // 4. 最大列数を計算する
    MaxColumns = List.Max(List.Transform(SplitLines[Column1], each List.Count(_))),
    
    // 5. 最大列数に合わせてヘッダーを生成 (Column1, Column2, ...)
    HeaderNames = List.Transform({1..MaxColumns}, each "Col" & Text.From(_)),
    
    // 6. 各行のリストを最大列数に合わせてパディング(足りない分はnullで埋める)
    Padding = Table.TransformColumns(SplitLines, {{"Column1", each List.Combine({_, List.Repeat({null}, MaxColumns - List.Count(_))})}}),
    
    // 7. リストをテーブルの列に展開
    ExpandTable = Table.FromRows(Padding[Column1], HeaderNames)
in
    ExpandTable

実務アドバイス:メンテナンス性を高めるための設計思想

実務において、この手法を採用する際は以下の3点に注意してください。

第一に「パフォーマンス」です。上記コードは非常に汎用性が高いですが、数ギガバイト規模の巨大なCSVに対して `List.Transform` を多用すると、メモリを大量に消費します。データ量が膨大な場合は、CSVの先頭数行のみをサンプリングして列数を判定する最適化を検討してください。

第二に「データ型の変換」です。動的に生成された列はすべて「任意の型(Any)」として扱われます。読み込み後のステップで `Table.TransformColumnTypes` を使い、明示的に型変換を行うことが推奨されます。列数が増減する可能性があるため、列名が存在するかを確認する `Table.HasColumns` 関数を併用したエラーハンドリングを実装すると、より堅牢なシステムになります。

第三に「ヘッダー処理」です。CSVの1行目が常にヘッダーであるとは限りません。もしヘッダー行が複雑な場合や、存在しない場合は、上記のコードをベースにして、1行目を昇格させる処理を柔軟に組み込む必要があります。可能であれば、CSVの仕様を抽出元システム側で統一するよう交渉することも、エンジニアとしての重要なスキルです。

まとめ:M言語をマスターしてデータエンジニアリングの壁を越える

列数不定のCSV取り込みは、多くのPower Queryユーザーにとっての「最初の壁」です。しかし、一度このM言語のロジック(行分割・パディング・テーブル化)を理解してしまえば、どんなに不完全なデータソースであっても、安定してExcelやPower BIへ取り込むことが可能になります。

VBAで何百行も書いていたCSV解析処理を、わずか十数行のM言語で完結させる。これこそが、現代のデータ分析における「スマートな自動化」です。本稿で紹介した手法をベースに、皆さんの業務環境に合わせてカスタマイズを行ってください。もし、さらなる複雑な要件(例えば、特定文字を含む行のみを抽出したい、あるいは列名に基づいて動的に列を並び替えたい等)が発生した場合は、`Table.SelectColumns` や `Table.ReorderColumns` といった関数を組み合わせることで、対応範囲は無限に広がります。

Power Queryは単なるデータ取り込みツールではありません。M言語という強力な関数型言語を内包した、最強のデータ変換エンジンです。ぜひ今日から、既存のインターフェースに依存せず、生のデータ構造を直接操作する感覚を掴んでください。それが、あなたの業務効率を桁違いに向上させる唯一の道です。

タイトルとURLをコピーしました