ABC-анализ на М
#АнатомияФункций – приёмы
Все привет!
Как насчёт задачки, чтоб аккумулятор с генератором, сортировками, группировками,буферами и комбайнами всякими?
Ну вот примерно такое и требуется, если ABC-анализ проводить на стороне PQ, да чтоб сразу по пачке столбцов, с сохранением порядка строк, блекджеком и … (хотя, когда закончите – они тоже не помешают).
В общем когда-то давно, на заре Мерки, я решил это так:
(таблица,группа,столбцы)=>
let
ABC=(tbl,col,colname)=>[
t = Table.Buffer(Table.Sort(tbl,{col,Order.Descending})),
r = List.Buffer(Table.Column(t,col)),
n = List.Count(r),s = List.Sum(r),
a = 0.5*s,b = 0.8*s,c = 0.95*s,
f=(x)=>if x<=a then "A" else if x<=b then "B" else if x<=c then "C" else "D",
g = List.Generate(()=>[i=0,j=r{i},k="A"],(x)=>x[i]<n,(x)=>[i=x[i]+1,j=r{i}+x[j],k=f(j)],(x)=>x[k]),
res = Table.FromColumns(Table.ToColumns(t)&{g},Table.ColumnNames(t)&{colname})][res],
add = Table.AddIndexColumn(таблица,"i"),
lst = List.Buffer(List.Transform(столбцы,(x)=>{x,"ABC_"&x})),
g=(tbl)=>List.Accumulate(lst,tbl,(s,c)=>ABC(s,c{0},c{1})),
gr=Table.Group(add,группа,{"t",g}),
exp = Table.ExpandTableColumn(gr,"t",List.Combine(lst)&{"i"}),
to = Table.RemoveColumns(Table.Sort(exp,"i"),"i")
in
to
Ну решил и забыл. А тут неожиданно в чат принесли код на оптимизацию, и я начал его переписывать… закрались сомнения – полез в архивы – понял, что переписываю сам себя из 2020 ))) Вот только переписать всё равно было необходимо, поэтому получилось такое:
(таблица,группа,столбцы)=>
[
ABC=(tbl,col,colname)=>[
t = Table.Buffer(Table.Sort(tbl,{col,Order.Descending})),
r = List.Buffer(Table.Column(t,col)),
n = List.Count(r),s = List.Sum(r),
a = g(0.5*s), b = g(0.8*s), c = g(0.95*s),
f=(x)=>if x<=a or x=0 then "A" else if x<=b then "B" else if x<=c then "C" else "D",
gen = List.Buffer(List.Generate(()=>[i=0,j=r{i}],(x)=>x[i]<n,(x)=>[i=x[i]+1,j=r{i}+x[j]],(x)=>x[j])),
g=(x)=>List.PositionOf(gen,x,Occurrence.Last,(c,v)=>v>=c),
res = Table.TransformColumns(Table.AddIndexColumn(t,colname),{colname,f})][res],
add = Table.AddIndexColumn(таблица,"i"),
lst = List.Buffer(List.Transform(столбцы,(x)=>{x,"ABC_"&x})),
g=(tbl)=>List.Accumulate(lst,tbl,(s,c)=>ABC(s,c{0},c{1})),
gr=Table.Group(add,группа,{"t",g}),
exp = Table.Combine(gr[t]),
to = Table.RemoveColumns(Table.Sort(exp,"i"),"i")][to]
Если думаете, что это практически тоже самое – ошибаетесь, оно отличается алгоритмически и при этом кратно шустрее )))
Ну а детали можно посмотреть:
На спонсоре с исходниками
На рутубе
На дзене
На ютубе
Лайк, коммент, подписка приветствуются )))
Надеюсь, было полезно.
Всех благ!
@buchlotnik