なんでもエクセル(Nandemo Excel)

何でもエクセルでやってしまう そこのあなた。ようこそ

Power Query:列のピボット その5(集計行を追加する)

前回これで最後と書いた癖に、もう一つ追加。

列のピボットで作成したマトリクス表に「集計行」を追加したい時どうするか。

「テーブルの最下行に1行追加ってどうやるの?」と悩んだ方は、Power Queryの便利な機能を一つ忘れている。「行列の入替」である。

縦横逆に集計して、カスタム列の追加で集計行(列だけど)を追加して、最後に行列を入れ替えてやればいいのだ。


「日付」列を選択した状態で[編集]→[列のピボット]

値列:件数 詳細設定オプションの値の集計関数:合計 →[OK]

これで縦横逆のマトリクス表が完成。後はカスタム列の追加を実行するだけ。こういう時に便利なのが「Record.FieldValues(_)」。何列あろうが同行の値をリストとして読み込んでくれる。列数が可変であっても関係なし。


[列の追加]→[カスタム列]

新しい列名:合計 カスタム列の式:= List.Sum(List.Skip(Record.FieldValues(_)))

「List.Skip」を挟んでいるのは、先頭の「日付」列を集計範囲から外すため。続いてカスタム列の追加で「個数」列を追加する。


新しい列名:個数 カスタム列の式:= List.NonNullCount(List.Skip(Record.FieldValues(_)))-1

最後に「-1」しているのは、一つ前に追加した合計列の分を引くため。

これでほぼ形は出来上がったので、最後の仕上げ。行列入替の前にヘッダーを先頭行に降格しておく。


[変換]→[1行目をヘッダーとして使用]→[ヘッダーを1行目として使用]

[変換]→[入れ替え]

これでおしまい。あとは「閉じて読み込む」で完成。

ただし一点だけ注意。今回は横軸が「日付」なので、あえて先頭行をヘッダに昇格していない(見出しにすると必ず「文字列」になってしまうから)。このままだと見苦しいので、


[テーブルデザイン] →テーブル スタイルのオプションの[見出し]のチェックを外す

これで見た目もすっきりする。行ごとの色付けや罫線はお好みで。

Power Query:行のグループ化 その2(個別の行数のカウント)

Excelで時々困るのが、「重複を省いて件数をカウントしたい」時。ダブっているものを1つとして計算したい時、ピボットテーブルでは単純に集計できない。

「田中太郎:3」、「鈴木一郎:2」になってくれないといけないのに、ピボットテーブルで集計すると個数をただカウントするだけになってしまう。

Microsoft365だったら数式で重複を省いてからカウントする手もあるにはある。

数式版(Microsoft365):
=LET(
    _unq,UNIQUE(テーブル1[氏名]),
    _byr,BYROW(_unq,LAMBDA(_a,
        ROWS(UNIQUE(FILTER(テーブル1,テーブル1[氏名]=_a)))
    )),
    VSTACK({"氏名","カウント"},HSTACK(_unq,_byr))
)

ただ他のバージョンだとやり方を間違えると(分母に COUNTIF/Sを入れて足すやつのこと。空白を除く処理も面倒)演算誤差が発生する。そうならないようにしようと思ったら配列計算になってしまう。対象が数値のみなら FREQUENCYでもできるけど……

ここはやはりクエリの出番だと思う。すんごい簡単だし。

まず例によって作成したテーブルからクエリを作成する。


[データ]→[テーブルまたは範囲から]

クエリができたら「氏名」列を指定してグループ化を実行する。


「氏名」列を選択して右クリック[グループ化]

新しい列名:カウント 操作:個別の行数のカウント →[OK]

これで完成。

これを指定のセル上に読み込めばおしまい。

nandemo-xl.hatenablog.com

Power Query:現金出納帳から勘定元帳を作る

先日、質問掲示板に Excelで現金出納帳を作っている人の質問があったんだけど、その人の出納帳には右端に残高列があって、そこから月ごとの残高が計算できなくて困っているという質問だった。……いや計算に使えなくて困るくらいならそんな列いらんでしょうよ。あんなもの手計算だった時代の名残りでしかないのに。

そう思ったんで「紙書類じゃないんだから、その列いらないんじゃない?」と突っ込んだら、「私の表にはいるんです!」と返された。何のこだわりなんだろう。

さて愚痴は置いといて、「現金出納帳(お小遣い帳)」を基にして他の帳票をクエリで作ってみよう。もちろん出納帳に残高列なんていらないし、月別にシートを分けるようなこともしない。

こういう現金出納帳を基にして勘定元帳を作ってみよう。

下準備は勘定科目の入力セルを決めて、そこに「勘定科目」と名前定義しておくだけ。

勘定元帳
let
    ブック = Excel.CurrentWorkbook(),
    勘定科目名 = ブック{[Name="勘定科目"]}[Content]{0}[Column1],
    ソース = ブック{[Name="テーブル1"]}[Content],
    型の変更 = Table.TransformColumnTypes(ソース, {
        {"日付", type date},
        {"科目名", type text},
        {"入金", Int64.Type},
        {"出金", Int64.Type},
        {"摘要", type text}
    }),
    繰越行の削除 = Table.Skip(型の変更),
    行の抽出 = Table.SelectRows(繰越行の削除, each [科目名]=勘定科目名),
    借方金額列の追加 = Table.AddColumn(
        行の抽出, "借方金額", each List.Sum({[出金], 0}), Int64.Type
    ),
    貸方金額列の追加 = Table.AddColumn(
        借方金額列の追加, "貸方金額", each List.Sum({[入金], 0}), Int64.Type
    ),
    連番列の追加 = Table.AddIndexColumn(
        貸方金額列の追加, "連番", 1, 1, Int64.Type
    ),
    累計列の追加 = Table.AddColumn(連番列の追加, "累計", each 
        List.Sum(List.FirstN(連番列の追加[借方金額], [連番])&{0})
    ),
    列の削除 = Table.RemoveColumns(累計列の追加, {"入金", "出金", "連番"})
in
    列の削除

以上。累計列以外はマウス操作でも普通に作れると思う。あくまでも現金出納帳から作る元帳なので、前期残はないものとする。

この形なら勘定科目セルの科目名を変更して「更新」してやれば抽出し直すので、シートを科目の数だけ増やすような無駄なことをしなくて済む。これを入力と同時に抽出される仕様にしたければ VBAで Worksheet_Changeイベントを入れてやればいい。

ついでに、科目別の月別収支表を作ってみよう。

行の並びを固定したいので、科目マスタを別に作っておこう。もちろん Excelで作ったテーブルを読み込んでもいい。

科目マスタ
let
    ソース = Table.FromColumns(
        {{"交通費", "燃料費", "通信費", "交際費", "福利厚生費"}},
        type table [科目名=text]
    )
in
    ソース

科目別の収支結果を「列のピボット」→「科目マスタにマージ」してやれば完成。

科目別月別収支
let
    ブック = Excel.CurrentWorkbook(),
    ソース = ブック{[Name="テーブル1"]}[Content],
    型の変更 = Table.TransformColumnTypes(ソース, {
        {"日付", type date},
        {"科目名", type text},
        {"入金", Int64.Type},
        {"出金", Int64.Type},
        {"摘要", type text}
    }),
    月名の表示 = Table.TransformColumns(
        型の変更, {"日付", each Date.MonthName(_), type text}
    ),
    収支列の追加 = Table.AddColumn(
        月名の表示, "収支", each List.Sum({[出金], -[入金], 0})
    ),
    列の削除 = Table.RemoveColumns(
        収支列の追加,{"入金", "出金", "摘要"}
    ),
    列のピボット = Table.Pivot(
        列の削除, List.Distinct(列の削除[日付]),
        "日付", "収支", List.Sum
    ),
    クエリのマージ = Table.NestedJoin(
        科目マスタ, {"科目名"},
        列のピボット, {"科目名"},
        "勘定科目"
    ),
    見出し = List.Skip(Table.ColumnNames(列のピボット)),
    列の展開 = Table.ExpandTableColumn(
        クエリのマージ, "勘定科目", 見出し
    ),
    値の置換 = Table.ReplaceValue(
        列の展開, null, 0, Replacer.ReplaceValue, 見出し
    )
in
    値の置換

こんな感じ。

Power Query:列のピボット その3

引き続き「列のピボット」。前回は縦軸用の番号列の作り方をやったけど、今回はn行一組のデータを、列のピボットを使って組み替えてみたい。

n行(画像だと4行)で一組のデータ(もちろんデタラメ)があるとして、

これを1行ずつのデータに組み換える場合の話。

行数が固定の時は「Table.Splitを使う方法」もあるにはある。そっちでやってももちろんいいんだけど、詳細エディタから M言語で記述しまくることになるので、慣れていない人にはしんどいと思う。なので今回はパス。

まずは上の画像の A:B列を「データ範囲」と名前定義しているものとする。

この状態で

[データ]→[テーブルまたは範囲から]

これでクエリが作成される。


右ペインの最終ステップ(画像だと「変更された型」)を右クリックし [後にステップの挿入]をクリック

すると、数式バーに「= 変更された型」が表示されるので、ここを下記のように書き換える。


数式を「= Table.FirstN(変更された型, each [Column1]<>null)」に

ひとまずここまで。やっていることは「Table.FirstN」で「一番上の行から null以外のデータを保持」しているだけ。


「Column1」を選択した状態で右クリック[グループ化]

ここで前回と同じく、グループ化の数式を書き換え。


数式バーを広げて黄色部分の「each _」となっているところを 「each Table.AddIndexColumn(_, "連番", 1, 1)」に変更 「type table [……]」の中に「, 連番=number」を追加

ここからは通常運行。縦軸用の「連番」列を展開してから列のピボットを実行すればおしまい。


「テーブル」列の見出しの右に表示されているアイコンをクリック 「Column2」と「連番」にチェックを入れる 「元の列名をプレフィックスとして使用します」のチェックを外す →[OK]

「Column1」を選択した状態で[編集]→[列のピボット] 値列:Column2 詳細設定オプションの値の集計関数:集計しない →[OK]

あとは「閉じて読み込む」で完成。

ひとくくりになる行が固定でない時は、別のアプローチが必要になるので、そっちはまた今度。

Power Query:列のピボット その2(縦軸用の列がない場合)

前回の続き。そこでもちらっと書いたけど、列のピボットを実行する時には、必ず縦横方向の軸となる値が必要になる。

この画像の場合だと、テーブル1には横軸となる「班」列はあるものの、テーブル2の「連番」を構成する縦軸用の列がない。このまま列のピボットを実行するとどうなるか。


「班」列を選択した状態で[変換]→[列のピボット]

[値列]に「名前」、[値の集計結果]に「集計しない」を選択して[OK]

すると結果は、

見事に失敗。

こうならないためには、予め班ごとに連番(インデックス)を振っておく必要がある。


「班」列を選択した状態で右クリック[グループ化]

「班」列を指定 新しい列名:テーブル 操作:すべての行 →[OK]

これでひとまずグループ化に成功。この後、テーブル列内のテーブルにインデックス列を追加するのだが、ここだけは手入力が必要。「縦方向のデータを横並びで出力する」にも書いたけど、いっそグループ化の式を数式バーから直接いじったほうが簡単だったりする。


数式バーを広げて黄色部分の「each _」となっているところを 「each Table.AddIndexColumn(_, "連番", 1, 1)」に変更 「type table [……]」の中に「, 連番=number」を追加

こうすることで、グループ化で作られたテーブルの中に連番列が追加される。そして簡単に展開もできる。


テーブル列の右にある小さいアイコンをクリック 「名前」と「連番」にだけチェックを入れる [元の列名をプレフィックスとして使用します]のチェックを外して[OK]

これで班ごとに連番を振ることができた。後は最初にやった「列のピボット」を今度こそ実行。


「班」列を選択した状態で[変換]→[列のピボット] [値列]に「名前」、[値の集計結果]に「集計しない」を選択して[OK]

これで望んでいる形に読み込むことができた。

Power Query:列のピボット その1

 今回は「列のピボット」を紹介する。Excelでいうピボットテーブル的な集計がしたい時に使う機能で、要は「列のピボット解除」の逆パターン。よく使う機能なんだけど、実のところ集計に使われることは少ないかと思う。

左表の「属性」列を横軸にして、右表のように組み換えする場合。例によってテーブルは読み込んでいるものとする。


「属性」列を選択した状態で[編集]→[列のピボット]

軸となる値列に「値」列を選択 詳細設定オプション[値の集計関数]で「集計しない」を選択

これで縦横の軸に情報が並んだマトリクス表に組み換えできた。

因みに詳細設定オプションには下記の種類がある。

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

ところで、この機能を使う時に注意しないといけないのが「番号」列である。これがないと組み換えはできない。例えば「属性」と「値」だけのテーブルでやってみると、

こうなってしまう。「集計なし」で利用する時は必ず属性ごとに設定された番号列が必要になることを覚えておいて欲しい。番号列がない場合は「グループ化」と「インデックス列の追加」で作ればいい。

nandemo-xl.hatenablog.com

Power Query:インデックス列の追加

これ単独でページ作るのもどうかと思うけど、クエリを作る過程でインデックス列(連番列)があると後々の計算の都合がいい場面が多々ある。実際マウス操作で行う場合、これなしでは先に進めない処理がいくつもある。グループ別に組み換えする時とか。

その連番列を追加する方法はいくつかある。

単純なのはマウスの操作で「インデックス列」をクリックすること。M言語では「Table.AddIndexColumn」を使う。


[列の追加]の[インデックス列]

これだけ。

この場合先頭は「0」から始まることになる。そのほうが他の計算に使う時は都合がいいけど、あえて「1」からにしたい場合は、


[列の追加]の[インデックス列]→[1から]

これでOK。

新規に連番列を持つテーブルを作りたい時は、下記の手順でできる。


[新しいクエリ]→[その他のソース]→[空のクエリ]

数式バーに「= {1..100}」と入力

余談ではあるが、対象がテーブルではなくリストだった場合は「List.Positions」を使うことで「0」からの連番が作れる。いちいち連番が必要だからと、リストをテーブルに変換する必要はない。

もう一つは読み込んだ後のテーブルに「番号列」を追加する方法。まずは何もせずに読み込む。

この状態で


[データ]→クエリと接続の[プロパティ]

データのレイアウトで[行番号を含む]にチェックを入れて[OK]

このままだと何の変化もないので一回更新が必要。


テーブルを選択した状態で右クリック[更新]

説明しておいてなんだけど、今更こんな方法を使う人はいないと思う。