Страницы: 1
RSS
Power Query - умножение каждого значения из многих строк и столбцов на константу по условию
 
Добрый день.
подскажите, пожалуйста.
Есть, например, такая таблица:
Код
let  
      Source = #table(   
        {"TRUE/FALSE", "Number 1", "Number 2"},    
          {     
              {true, 1, 10},     
              {true, 2, 15},
              {false,2, 20},
              {true, 5, 8}, 
              {false, 1, 3},     
              {false, 6, 6},
              {false, 7, 7},
              {true, 5, 12},   
              {true, 4, 14},     
              {true, 6, 9} 
          })
    in  
        Source


На самом деле в ней миллионы строк и очень много числовых столбцов.

Мне бы сделать формулой такую математику: если в коронке 1 treu, то в данной строке в каждой из колонок (колонок много, т.е. нельзя перечислять их вручную) число умножить на 10, а если fakse - на 20.

Вот вроде просто должно быть,  но я совсем неумеха пока.
Помогите, плиз.
Изменено: Kirill Gureev - 05.03.2021 10:39:13
 
del
Изменено: buchlotnik - 23.08.2021 15:30:38
Соблюдение правил форума не освобождает от модераторского произвола
 
Еще вариант
Код
let
      a = #table(   
        {"TRUE/FALSE", "Number 1", "Number 2"},    
          {     
              {true, 1, 10},     
              {true, 2, 15},
              {false,2, 20},
              {true, 5, 8}, 
              {false, 1, 3},     
              {false, 6, 6},
              {false, 7, 7},
              {true, 5, 12},   
              {true, 4, 14},     
              {true, 6, 9} 
          }),
    b = List.Select(Table.ColumnNames(a), each _<>"TRUE/FALSE")
 in Table.ReplaceValue(a, each [#"TRUE/FALSE"],10,(a,b,c)=> if b then c*a else 20*a,b)
 
buchlotnik, я пытаюсь детально разобрать Ваше решение.
У меня пока получается так:

Шаг 1: Таблица преобразуется в записи:
tbl = Table.ToRecords(from),
Шаг 2: Указывается применение к записям функции g:
trnsf= List.Transform(tbl,g),
Шаг 3: Производится проверка для каждой записи x [#"TRUE/FALSE"]:
g=(x)=> if x[#"TRUE/FALSE"]=true then f(x,10) else f(x,20),
и в зависимости от результата с параметрами переходим дальше:
Шаг 4: Для каждой записи вызывается разный f: then f(x,10) else f(x,20):
f=(x,y)=>List.Accumulate(lst,x,(s,c)=>Record.TransformFields(s,{c,(x)=>x*y})):

И вот возник вопрос... от откуда берётся x и что это?
 
del
Изменено: buchlotnik - 23.08.2021 15:30:56
Соблюдение правил форума не освобождает от модераторского произвола
 
Kirill Gureev, если не сложно то после сравнения на вашем большом объеме скажите какая разница в скорости?
Мое мнение вариант от Михаила с красной пробиркой будет быстрее.
Вот горшок пустой, он предмет простой...
 
Цитата
PooHkrd написал:
какая разница в скорости?
на 10k

Цитата
PooHkrd написал:
с красной пробиркой
колба, пробирка прозрачная и бесцветная  ;)
Изменено: buchlotnik - 05.03.2021 20:25:53
Соблюдение правил форума не освобождает от модераторского произвола
 
Цитата
buchlotnik написал:
пробирка прозрачная
Ай! Пардоньте. Я далек от химии, могу и перепутать.
Вот горшок пустой, он предмет простой...
 
Доброе время суток.
Ещё вариант
Код
let
    Source = Excel.CurrentWorkbook(){[Name="Таблица1"]}[Content],
    f10 = (x) => if x is logical then x else 10 * x,
    f20 = (x) => if x is logical then x else 20 * x,
    methods = List.Transform(Source[#"TRUE/FALSE"], each if _ then f10 else f20),
    zip = List.Zip({methods, Table.ToRows(Source)}),
    calc = List.Transform(zip, (pair) => List.Transform(pair{1}, pair{0})),
    toTable = Table.FromRows(calc, Table.ColumnNames(Source))
in
    toTable

На честных 255 столбцах (первый с именем "TRUE/FALSE" и значениями true/false) и 10000 строк.
Updated. Чуть похимичил :)
buchlotnik 99 секунд;
у меня 22 секунды19,5 секунд
Изменено: Андрей VG - 05.03.2021 21:22:34
 
buchlotnik,  Я окончательно спёкся на вот этой строке:

Код
f=(x,y)=>List.Accumulate(lst,x,(s,c)=>Record.TransformFields(s,{c,(x)=>x*y})):


Помогите, плиз! Что это?
 
Цитата
Kirill Gureev написал:
Что это?
это функция двух переменных - x и y - которая проходит по списку lst (первый аргумент List.Accumulate и по совместительству список всех изменяемых столбцов) и совершает преобразование с x (напоминаю, мы туда передаем запись); суть преобразования - изменить поле записи (Record.TransformFields) с текущего на текущее*y

это конечно не моё дело, но может стоит справку по PQ почитать? там интересно...
Изменено: buchlotnik - 05.03.2021 22:31:51
Соблюдение правил форума не освобождает от модераторского произвола
 
Всё-таки неисповедимы пути оптимизации в PQ. Пытался что-то сварганить с List.Generate - всё равно запрос выполнялся процентов на 60 дольше, чем у Андрей VG. Сделал элементарно - всё летает. Чудеса-чудеса - небывальщина...

Вариант без сортировки строк:
Код
let
  Source = data,
  cols = List.Buffer(List.Skip(Table.ColumnNames(Source))),
  final = Table.TransformColumns(
    Table.SelectRows(Source, each [#"TRUE/FALSE"]),
    List.Transform(cols, (x) => {x, each _ * 10})
  )
    & Table.TransformColumns(
      Table.SelectRows(Source, each not [#"TRUE/FALSE"]),
      List.Transform(cols, (x) => {x, each _ * 20})
    )
in
  final

Чуть медленнее - с сортировкой:
Код
let
  Source = data,
  i = Table.AddIndexColumn(Source, "i"),
  cols = List.Buffer(List.RemoveItems(Table.ColumnNames(i), {"TRUE/FALSE", "i"})),
  transform = Table.TransformColumns(
    Table.SelectRows(i, each [#"TRUE/FALSE"]),
    List.Transform(cols, (x) => {x, each _ * 10})
  )
    & Table.TransformColumns(
      Table.SelectRows(i, each not [#"TRUE/FALSE"]),
      List.Transform(cols, (x) => {x, each _ * 20})
    ),
  final = Table.RemoveColumns(Table.Sort(transform, {"i", 0}), "i")
in
  final
Изменено: Aleksei_Zhigulin - 06.03.2021 01:52:54
 
Цитата
Aleksei_Zhigulin написал:
неисповедимы пути оптимизации в PQ
Ой, и не говорите.... Большое спасибо, Алексей! Ваш вариант - 10 секунд.
Updated.
Для сравнения - код на VBA выполняется 2,6 секунды.  :D
Скрытый текст
Изменено: Андрей VG - 06.03.2021 10:39:08
 
Понял, насколько мог. Спасибо.
Страницы: 1
Наверх