4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Power Query] 1列に積み重なったデータを表形式にするベストプラクティスは? (1) Table.AddIndexColumn → Table.Pivot

Last updated at Posted at 2023-07-30

※この記事は 2023/7/22 に作成しました。
※オプションで、「地域の設定」の「クエリステップ」は、「常に英語」に設定されています。日本語で使用している場合は、各自環境で作成されるコードに読み替えてください。

Index

課題: 1列に積み重なったデータの整形

 様々な整形されていないデータを扱っていると、以下のような形式のデータを扱うことがあります。

鬼滅の刃 10
[著]吾峠呼世晴
2018/03/01
鬼滅の刃 11
[著]吾峠呼世晴
2018/06/01
鬼滅の刃 12
[著]吾峠呼世晴
2018/08/01
鬼滅の刃 13
[著]吾峠呼世晴
2018/11/01

 上記の例では、書名、著者名、出版日の3つの項目が1列に積み重なっています。これを、以下の表形式にする方法を紹介し、どれが一番いいのか比較してみます。

書名 著者名 出版日
鬼滅の刃 10 [著]吾峠呼世晴 2018/03/01
鬼滅の刃 11 [著]吾峠呼世晴 2018/06/01
鬼滅の刃 12 [著]吾峠呼世晴 2018/08/01
鬼滅の刃 13 [著]吾峠呼世晴 2018/11/01
  • 参考とした記事: @PowerBIxyz(Takeshi Kagata)さんの「Power Query workout - Table.AlternateRows / List.Alternate」
    かなり深い話なので、この記事だけで何の話か理解できた人は、かなりの強者です。私も20回回ったくらいでやっと何の話か分かった気がします。

  • 今回使用するデータ: メディア芸術データベース・ラボの「データセットダウンロード」からjson形式のデータを変換して使用させていただきました。

解法1: ピボットを使用する

 Power Queryのピボット機能を使って行うことができます。この方法は、ブログやYoutubeで紹介されることが多く、とても人気のある方法です。

Table.AddIndexColumn

 元のデータは、値値となります。ここに行見出しと列見出しを「列の追加」で作成していきます。

 まず、「列の追加」タブで「全般」グループの「インデックス列(0から)」を選択します。

Table.AddColumn

 次に、追加された「インデックス」列を選択して、「列の追加」タブで「数値から」グループの「標準」→「剰余」を選択し、値に項目数の3を入れると、0~2を繰り返す値が設定され、これが列見出しになります。

Table.TransformColumns

 行見出しは、先に作成した「インデックス」列を変換します。
 「変換」タブで「数値の列」グループの「整数」→「整数除算」を選択し、値に列数の3を入れます。

 変換を実行すると、以下のようになります。

Table.Pivot

 列見出しになる「剰余」列を選択し、「変換」タブで「任意の列」グループの「列のピボット」を選択します。「列のピボット」のダイアログが表示されますので、値列となる Column1 と、値の集計関数に「集計しない」を選択してOKを押します。

 以下のようなテーブルが出来上がりますので、最後に「インデックス」列を削除すれば完成です。

Table.Pivot関数解説

 Table.Pivot関数の構文は以下の通りです。

構文
Table.Pivot(
    table as table, 
    pivotValues as list, 
    attributeColumn as text, 
    valueColumn as text, 
    optional aggregationFunction as nullable function
) as table

 pivotValues には、列見出しとなる項目のリスト、 attributeColumn は列見出しとなる項目の列名を設定します。そして、 valueColumn は、値列の列名を設定します。また、 optional には、集計関数を設定します。

集計関数名 関数
カウント(すべて) List.Count
カウント(空白なし) List.NonNullCount
最小値 List.Min
最大値 List.Max
中央 List.Median

 集計しない場合は、optional は設定されません。

 今回の処理で作成されたコードは、以下のようになっていました。(適宜改行&インデントしています)

Table.Pivot
PivotedColumn = Table.Pivot(
    Table.TransformColumnTypes(
        IntegerDividedColumn, 
        {
            {
                "剰余", 
                type text
            }
        }, 
        "ja-JP"
    ),
    List.Distinct(
        Table.TransformColumnTypes(IntegerDividedColumn, 
        {
            {
                "剰余", 
                type text
            }
        }, 
        "ja-JP"
    )[剰余]),
    "剰余",
    "Column1"
),

 Table.Pivotの第一引数と第二引数の中で Table.TransformColumnTypes が行われています。これは、列見出しとなる項目が10進数型になっていたため、ピボットするためにテキスト型に変換する必要があるからです。事前にテキスト型に変換するステップ「Changedtype」を挿入しておけば、Table.Pivotの引数は以下のようにすっきりした形になります。

PivotedColumn = Table.Pivot(
    ChangedType, 
    List.Distinct(
        ChangedType[剰余]
    ), 
    "剰余", 
    "Column1"
)

Table.Pivotの第二引数は、 ChangedType[剰余] として値のリストを抽出した後に List.Distinct で重複を削除しています。

ソースコード

 今回のコードの全体は、以下のようになっています。

let
    // ファイルの読み込み
    Source = Table.FromColumns(
        {
            Lines.FromBinary(
                File.Contents( "** File Name **" ),
                null,
                null,
                932  // シフトJIS
            )
        }
    ),
    // インデックス列の追加(0から始まる)
    AddedIndex = 
        Table.AddIndexColumn(
            Source, 
            "インデックス", 
            0, 
            1, 
            Int64.Type
        ),
    // 列見出しを作成
    InsertedModulo = 
        Table.AddColumn(
            AddedIndex, 
            "剰余", 
            each Number.Mod([インデックス], 3), 
            type number
        ),
    // 行見出しを作成
    IntegerDividedColumn = 
        Table.TransformColumns(
            InsertedModulo, 
            {
                {
                    "インデックス", 
                    each Number.IntegerDivide(_, 3), 
                    Int64.Type
                }
            }
    ),
    // ピボット前に型変換を行う
    ChangedType = 
        Table.TransformColumnTypes(
            IntegerDividedColumn, 
            {
                {"剰余", type text}
            }
        ),
    // 剰余列に対してピボットを行う
    PivotedColumn = 
        Table.Pivot(
            ChangedType,
            List.Distinct(ChangedType[剰余]),
            "剰余",
            "Column1"
        ),
    // インデックス列削除
    RemovedColumns = Table.RemoveColumns(PivotedColumn, {"インデックス"}),
    // 項目名変更
    RenamedColumns = 
        Table.RenameColumns(
            RemovedColumns, 
            {
                {"0", "書名"}, 
                {"1", "著者名"}, 
                {"2", "出版日"}
            }
        )
in
    RenamedColumns
4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?