4
3

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 workout - Table.ReplaceValue

Posted at

指定する列の値を置換するときに使うよね。普通に使っていれば何の問題もない。ただ、動作や性能の考慮をしたほうがよいねと。クエリの評価パフォーマンスの低下に気を使わないのはよくないと思うのです。

Table.ReplaceValue(
    table as table,
    oldValue as any,
    newValue as any,
    replacer as function,
    columnsToSearch as list
) as table

構文には複雑さはない。ボタンポチポチでも利用できるし。

動作を知る

たとえば、Column1 / Column2 / Column3 に含まれる値のうち 0 を 2 に置換するときのクエリは次の通り。

Power Query
let
    Source = SourceTable,
    ReplacedValue = Table.ReplaceValue(
        Source,
        0, 2,
        Replacer.ReplaceValue,
        {"Column1", "Column2", "Column3"}
    )
in
    ReplacedValue

同じ結果を得るために Table.TransformColumns による別の記述も可能。

Power Query
let
    Source = SourceTable,
    TransfromColumns = Table.TransformColumns(
        Source,
        {
            {"Column1", each if _ = 0 then 2 else _, type number},
            {"Column2", each if _ = 0 then 2 else _, type number},
            {"Column3", each if _ = 0 then 2 else _, type number}
        }
    )
in
    TransfromColumns

また、Table.AddColumn による記述でも同じ結果を得ることができる。

Power Query
let
    Source = SourceTable,
    Added_Column1 = Table.AddColumn(
        Source, "_Column1",
        each if [Column1] = 0 then 2 else [Column1],
        type number
    ),
    Select_Columns1 = Table.SelectColumns(
        Added_Column1,
        {"_Column1", "Column2", "Column3"}
    ),
    Renamed_Column1 = Table.RenameColumns(
        Select_Columns1,
        {"_Column1", "Column1"}
    ),
    Added_Column2 = Table.AddColumn(
        Renamed_Column1,
        "_Column2",
        each if [Column2] = 0 then 2 else [Column2],
        type number
    ),
    Select_Columns2 = Table.SelectColumns(
        Added_Column2,
        {"Column1", "_Column2", "Column3"}
    ),
    Renamed_Column2 = Table.RenameColumns(
        Select_Columns2,
        {"_Column2", "Column2"}
    ),
    Added_Column3 = Table.AddColumn(
        Renamed_Column2,
        "_Column3",
        each if [Column3] = 0 then 2 else [Column3],
        type number
    ),
    Select_Columns3 = Table.SelectColumns(
        Added_Column3,
        {"Column1", "Column2", "_Column3"}
    ),
    Renamed_Column3 = Table.RenameColumns(
        Select_Columns3,
        {"_Column3", "Column3"}
    )
in
    Renamed_Column3

同じ結果を得ることができるこれら 3つクエリは、クエリフォールディングを等しく適切に利用することが可能。Table.ReplaceValue は Table.AddColumn → Table.SelectColumns → Table.RenameColumns の動作をするから、クエリの評価パフォーマンスも同じで差は発生しない。ステップが増えるから、列の追加を利用しているから、という理由でパフォーマンスが低下することはない。

評価パフォーマンスが低下する使い方

確かめれば明白。
Table.ReplaceValue をボタンポチポチで使うとき、newValue パラメータには "値" が指定されるわけだけど、引数を評価式にすることで便利に使おうとしているのかもだ。同じ行に含まれる列の値に置換したいといっても、確実に評価パフォーマンスの低下が発生するので使わない。クエリフォールディングが期待できないっていう時点で使わないのである。

17.0 ~ 18.0 sec

Power Query
let
    Source = SourceTable,
    ReplacedValue = Table.ReplaceValue(
        Source,0,
        each [Column1],Replacer.ReplaceValue,
        {"Column2"}
    ),
    ChangedType = Table.TransformColumnTypes(
        ReplacedValue,
        {"Column2", type number}
    )
in
    ChangedType

17.0 ~ 18.0 sec

Power Query
let
    Source = SourceTable,
    ReplacedValue = Table.ReplaceValue(
        Source,0,
        each [Column1],Replacer.ReplaceValue,
        {"Column3"}
    ),
    ChangedType = Table.TransformColumnTypes(
        ReplacedValue,
        {"Column3", type number}
    )
in
    ChangedType

1.7 ~ 2.0 sec

Power Query
let
    Source = SourceTable,
    AddedConditionalColumn = Table.AddColumn(
        Source, "_Column2",
        each if [Column2] = 0 then [Column1] else [Column2],
        type number
    ),
    RemovedOtherColumns = Table.SelectColumns(
        AddedConditionalColumn,
        {"Column1", "_Column2", "Column3"}
    ),
    RenamedColumns = Table.RenameColumns(
        RemovedOtherColumns,
        {"_Column2", "Column2"}
    )
in
    RenamedColumns

1.7 ~ 2.0 sec

Power Query
let
    Source = SourceTable,
    AddedConditionalColumn = Table.AddColumn(
        Source, "_Column3",
        each if [Column3] = 0 then [Column1] else [Column3],
        type number
    ),
    RemovedOtherColumns = Table.SelectColumns(
        AddedConditionalColumn,
        {"Column1", "Column2", "_Column3"}
    ),
    RenamedColumns = Table.RenameColumns(
        RemovedOtherColumns,
        {"_Column3", "Column3"}
    )
in
    RenamedColumns

type any から type number への変換が必要 : 1 sec 程度 追加されるものの、明らかに評価パフォーマンスが低下する。条件列の追加 → 列の選択 → 列名の変更 はGUI操作でできるのだから、こっちのほう使った方がよいのでは?と。

思ったこと🙄

どのようなクエリ記述するかはご自由にどうぞ。でもさ、利用できるリソースには限りがあるのだから細かいことであっても気にすべきだと思うね。

観察すべきことがどこまで計測できるかというこだわりはないけれども、比較するには充分な状況を確認することができる。

Power Query
// RowCount
2000000 meta [IsParameterQuery=true, Type="Number", IsParameterQueryRequired=true]

// SourceTable
Table.FirstN(
    Table.FromColumns(
        {
            List.Generate(()=>1, each true, each 1),
            List.Generate(()=>0, each true, each 0),
            List.Generate(()=>0, each true, each List.Max({0,1}, null, _))
        },
        type table [Column1 = number, Column2 = number, Column3 = number]
    ),
    RowCount
)

その他

4
3
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
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?