精华内容
下载资源
问答
  • PowerBI星球嘉宾数据分析爱好者,擅长PBI数据分析一模型介绍帕累托法则 在任何组东西中,最重要的只占其中小部分,约20%,其余80%尽管是多数,却是次要的,因此又称二八定律。该法则在企业中可解读为20%的销售...
    ​文/Beau
    PowerBI星球嘉宾数据分析爱好者,擅长PBI数据分析

    一、模型介绍帕累托法则
    在任何一组东西中,最重要的只占其中一小部分,约20%,其余80%尽管是多数,却是次要的,因此又称二八定律。
    该法则在企业中可解读为20%的销售来自于80%的顾客,因此在面向这部分顾客,进行有重点、有针对性的服务。当然在对产品,渠道等多个销售维度分析都具有普适性。在实际销售场景中,可利用此法则快速定位头部客户,主力产品等,从而有效提升销售效率。
    本文模型基于帕累托法则核心要义,结合零售行业数据,利用Power BI进行建模及可视化多级动态展现。
    具体如下图:

    c1719efb539ed7b2639358e96e42228d.png


    具体布局及实现功能如下:1.切片区 (红框)
    KPI,单位,轴维度,配色方案,层级一。可对各字段进行动态切片选择。
    配色方案切片:仅对帕累托图有效。
    轴维度切片:对帕累托图X轴进行动态切换。
    层级一切片:可对层级一的项目进行选择,实现选择项的相对累计占比动态显示。

    9573502f71adcdcb08448c6013cd57a0.gif

    2.数值筛选区(黄框)
    日期,ABC占比,色彩饱和度。
    色彩饱和度同配色方案切片,仅对帕累托图有效。

    a4b009c84e7d0a8fb40b6abfbc80bcc8.gif

    3.信息提示区(蓝框)
    筛选清除按钮,信息提示按钮,下钻信息按钮。
    筛选清除按钮:一键初始化切片器。
    信息提示按钮:便于读者对模型的解读,对重点信息进行提示。
    下钻信息按钮:对当前是否可下钻进行判断,可通过按钮点击进行下钻跳转。

    bdabcd05d89fe1990b13ca20df1bb8f3.gif

    4.帕累托图表区(绿框)
    矩阵伸缩按钮,视觉对象标头动图工具提示。
    矩阵伸缩按钮:可通过点击实现矩阵表的展开和缩回,搭配帕累托图,数据信息展现更加全面。
    视觉对象标头动图工具提示:对在图表区可以使用的三种下钻方式进行提供动图化的工具提示,能让初次看到的读者快速了解使用方法。

    2403548960eca075f33242e928565d6f.gif

    今天这篇文章的内容将围绕如何实现多级下钻来进行展开。至于其他细节技巧,在后续文章中会有深度解读。二、何为多级帕累托
    图表的多级下钻对于熟悉PBI的小伙伴来说并不陌生,当数据结构为多个层级时,可以通过下钻实现对每个层级的展现分析。
    目前在网上能看到很多关于帕累托可视化以及图表多级下钻的教程,但对于两者的结合,目前却没找到现成的资料和教程,于是心血来潮,想尝试实现多级帕累托,于是便有了此模型。三、解决思路
    对于实现多级下钻,总的来说需要做好两个方面的工作:1.建立多层级字段表:比如要建立 产品类别--产品子类别的层级关系表,常规维度表一般都会具备这样的层级结构。2.建立相应度量值:一般这是实现多级可下钻的关键所在。
    下面我们就对度量值的构建进行重点解读。四、具体步骤1.建立维度表
    这里我们以产品维度为例,进行多级下钻的展示。维度表如下图所示:

    ac3852ca9712890d606ea248eafbed9b.png


    上图可以看到产品表中已存在产品类别-产品子类别的层级结构。
    那么对于轴下钻以及KPI度量值已无问题,那么接下来重点就是累计占比度量值的构造。2.构造累计占比度量值
    首先我们理一下构造逻辑:

    • 当前层级为一层级(产品类别)时,显示一层级各项目的累计占比,同时可以进行切片筛选。
    • 当前层级为二层级(产品子类别)时,显示二层级各项目的累计占比,同时可以进行切片筛选。

    很显然,根据上面的逻辑,这里首先要对当前所处层级进行判断,然后进行相应计算即可,那么这里需要用到一个关键函数-ISINSCOPE,可以利用此函数判断当前层级。
    那么累计占比度量值可以顺利写出:
    ----------累计占比(%) =

    VAR cur = [KPI]

    VAR grand_leve1 = CALCULATE( [KPI], FILTER ( ALLSELECTED ( '产品'[产品类别] ), [KPI] >= cur ) )

    VAR grand_leve2 = CALCULATE( [KPI], FILTER ( ALLSELECTED ( '产品'[产品子类别] ), [KPI] >= cur ) )

    VAR is_leve1 = ISINSCOPE( '产品'[产品类别] )

    VAR is_leve2 = ISINSCOPE( '产品'[产品子类别] )

    RETURN

    SWITCH( TRUE(), is_leve1&& NOT ( is_leve2 ), DIVIDE ( grand_leve1, CALCULATE ( [KPI],ALLSELECTED ( '产品'[产品类别] ) ) ), DIVIDE( grand_leve2, CALCULATE ( [KPI], ALLSELECTED ( '产品'[产品子类别] ) ) ) )

    ----------
    以上DAX中要注意ALLSELECTED的使用,这里是能够实现对层级项进行切片动态显示相对累计占比的关键。至于ABC分类配色度量等度量采大公号里有相关文章,不再赘述。
    接下来的步骤就很简单了,创建折线和堆积柱形图,拉入相关字段值,这样一个多级可下钻的帕累托图就呈现在面前了。

    f8dc2bb280d74d058e802a888aa4923e.png

    五、说在最后
    其实从本质上看,实现多级下钻的关键在于累计占比度量的构建,那么从本文中的方法可以发散扩展到其他任意可视化对象的下钻,其逻辑是相同的。
    看到这里,可能有小伙伴会问,能否实现在下钻到第二层级也可以进行类似第一层级的切片筛选?能否实现三级下钻?
    关于以上及更多的问题,你需要做的就是点击篇头模型链接,进去慢慢品,慢慢发现,可以的话也尝试做一下,你的收获会更大。
    正像文章开头所说,今天这篇文章的内容将主要围绕如何实现多级下钻来进行展开。关于模型更多的细节和技巧处理,如大家感兴趣后期会继续写文进行深度讲解。
    关于帕累托,关于多级下钻以及更多好的建议,欢迎小伙伴们与我一起交流。


    -精彩推荐-

    采悟:Power BI财务报表分析:手把手教你制作一个动态财务分析报告zhuanlan.zhihu.com
    96b14e6c10a057b779850cab2e14ceaa.png
    采悟:Power BI时间序列分析用到的度量值,一次全给你zhuanlan.zhihu.com
    3515cf28f09d259215c4d9ae6391bb70.png
    采悟:如何使用Power BI进行回流客户分析?zhuanlan.zhihu.com
    79dcbb5865f7699a0d529dcf78e3cc7a.png

    b0e0abfa21059b082b325421b6603f3c.png

    有帮助别忘了点赞哦。

    展开全文
  • 写在前面(本专栏仅是个人笔记本,有胡言乱语和错漏处, )这篇笔记结合汇编代码和fdump-class-hierarchy分析了GCC中多重继承下的对象在内存中的对象模型,以及虚函数表、动态绑定的底层实现。更具体的说,将个...

    写在前面

    (本专栏仅是个人笔记本,有胡言乱语和错漏之处, )

    这篇笔记结合汇编代码和fdump-class-hierarchy分析了GCC中多重继承下的对象在内存中的对象模型,以及虚函数表动态绑定的底层实现。

    更具体的说,将一个派生类赋给基类指针(引用)时发生了什么?使用基类指针调用虚函数的时候又发生了什么?

    编译器会在这两个过程中做一些幕后工作,使得正确的虚函数被调用正确的数据成员被访问

    看完这篇笔记,就能明白为什么Effective C++强烈建议:

    • Item 36: 绝不要重定义一个 inherited non-virtual function(通过继承得到的非虚拟函数)原因: 非虚函数编译期静态绑定
    • Item 37: 绝不要重定义一个函数的 inherited default parameter value(通过继承得到的缺省参数值)原因:C++的虚函数表里根本没有默认参数的位置,所以不可能在运行时动态绑定默认参数,只能在编译器决定。

    还有记住一点,在本文中,引用即指针,指针即引用,在涉及到虚函数的时候,它们没有任何区别。

    单重继承

    单重继承比较简单,只需保证虚函数表中的虚函数地址正确即可。

    多重继承下的汇编代码分析

    多重继承除了保证虚函数表正确,还要保证this指针在动态绑定以及调用虚函数时指向了正确的地址。

    以C继承A,B为例:

    class Class_A{
    public:
        virtual void fa(){}
        int ia;
    };
    
    class Class_B{
    public:
        virtual void fb(){}
        int ib;
    };
    
    class Class_C : public Class_A, public Class_B {
    public:
        virtual void fa(){}
        virtual void fb(){}
        virtual void fc(){}
        int ic;
    };
    
    
    int main(int argc, char const *argv[])
    {
        Class_A a;
        Class_B b;
        Class_C c;
        int temp;
        Class_A &ref_A = c;
        Class_B &ref_B = c;
        Class_C *pc = &c;
    
        ref_A.fa();
        temp = ref_A.ia;
        ref_B.fb();
        temp = ref_B.ib;
        pc->fc();
        temp = pc->ic;
        return 0;
    }
    

    gcc 可以通过(Before gcc 8.0 : fdump-class-hierarchy; after 8.0 : -fdump-lang-class)

    g++ -fdump-class-hierarchy main.cpp

    由此得到内存模型:

    Vtable for Class_A
    Class_A::_ZTV7Class_A: 3 entries
    0     (int (*)(...))0
    8     (int (*)(...))(& _ZTI7Class_A)
    16    (int (*)(...))Class_A::fa
    
    Class Class_A
       size=16(加上padding占用的大小) align=8
       base size=12(实际占用的大小) base align=8
    Class_A (0x0x402cdc8) 0
        vptr=((& Class_A::_ZTV7Class_A) + 16)
    
    Vtable for Class_B
    Class_B::_ZTV7Class_B: 3 entries
    0     (int (*)(...))0
    8     (int (*)(...))(& _ZTI7Class_B)
    16    (int (*)(...))Class_B::fb
    
    Class Class_B
       size=16 align=8
       base size=12 base align=8
    Class_B (0x0x402ce38) 0
        vptr=((& Class_B::_ZTV7Class_B) + 16)
    
    Vtable for Class_C
    Class_C::_ZTV7Class_C: 8 entries
    0     (int (*)(...))0
    8     (int (*)(...))(& _ZTI7Class_C)
    16    (int (*)(...))Class_C::fa
    24    (int (*)(...))Class_C::fb
    32    (int (*)(...))Class_C::fc
    40    (int (*)(...))-16
    48    (int (*)(...))(& _ZTI7Class_C)
    56    (int (*)(...))Class_C::_ZThn16_N7Class_C2fbEv
    
    Class Class_C
       size=32 align=8
       base size=32 base align=8
    Class_C (0x0x4028ac0) 0
        vptr=((& Class_C::_ZTV7Class_C) + 16)
      Class_A (0x0x402cea8) 0
          primary-for Class_C (0x0x4028ac0)
      Class_B (0x0x402cee0) 16
          vptr=((& Class_C::_ZTV7Class_C) + 56)
    

    这里有一个有意思的地方:

    6e5685f7c0fe8f5a07901e4f2e3a48a6.png

    C中B之前有padding,我的猜测是vptr_B要占8byte,而0xc不能被8整除,所以要从0x10开始放。


    言归正传,首先明确一点,vptr(虚函数指针)指向虚函数表(vtable)第2项。

    vtable for Class_C, 8 entries :在这个程序中,Class_C的虚函数表首地址为0x4e2f20。

    gdb中查看memory:

    f479b4915c591ba2845131d32686e229.png

    在调试器中可以看到,B的虚函数表首地址vptr_B = vptr_C + 0x38(0x4e2f58),那么0x4e2f58处本应是Class_C::fb,但是为了将this指针校准到c的起始位置,所以0x4e2f58处填的不是Class_C::fb,而是一个跳转函数(好像叫做thunk),它长这样:

        Dump of assembler code for function _ZThn16_N7Class_C2fbEv:
                0x00000000004b1be0 <+0>:tsub    $0x10,%rcx //%rcx即this
                0x00000000004b1be4 <+4>:tjmpq   0x4213f0 <Class_C::fb()>
    

    将之前给出的程序反汇编,得到如下汇编代码

    0x000000000040180f  callq  0x40c0f0 <__main>
    //定义变量,调用构造函数
    0x0000000000401814  lea    -0x30(%rbp),%rax
    0x0000000000401818  mov    %rax,%rcx
    0x000000000040181b  callq  0x421350 <Class_A::Class_A()>
    0x0000000000401820  lea    -0x40(%rbp),%rax
    0x0000000000401824  mov    %rax,%rcx
    0x0000000000401827  callq  0x4213a0 <Class_B::Class_B()>
    0x000000000040182c  lea    -0x60(%rbp),%rax
    0x0000000000401830  mov    %rax,%rcx
    0x0000000000401833  callq  0x421410 <Class_C::Class_C()>
    //ref_A = c
    0x0000000000401838  lea    -0x60(%rbp),%rax
    0x000000000040183c  mov    %rax,-0x8(%rbp)
    //ref_B = &c + 0x10
    //&c + 0: c的虚函数表地址 vptr_C(也是vptr_A)
    //&c + 0x8 : A::ia
    //&c + 0xc : padding吗? 好像是的
    //&c + 0x10 : vptr_B
    0x0000000000401840  lea    -0x60(%rbp),%rax
    0x0000000000401844  add    $0x10,%rax
    0x0000000000401848  mov    %rax,-0x10(%rbp)
    //pc = &c;
    0x000000000040184c  lea    -0x60(%rbp),%rax
    0x0000000000401850  mov    %rax,-0x18(%rbp)
    //ref_A.fa();
    0x0000000000401854  mov    -0x8(%rbp),%rax
    0x0000000000401858  mov    (%rax),%rax //%rax = vptr_A
    0x000000000040185b  mov    (%rax),%rdx //A的虚函数表第一项
    0x000000000040185e  mov    -0x8(%rbp),%rax //ref_A即this
    0x0000000000401862  mov    %rax,%rcx
    0x0000000000401865  callq  *%rdx
    //temp = ref_A.ia;
    0x0000000000401867  mov    -0x8(%rbp),%rax
    0x000000000040186b  mov    0x8(%rax),%eax
    0x000000000040186e  mov    %eax,-0x1c(%rbp)
    //ref_B.fb();
    //%rip 是指令寄存器 always points to next instruction
    //%rip此时为0x0000000000401878
    //%rip + 0xb0368 = 0x4b1be0
    //在gdb中反汇编该地址
    //>>>(gdb) disassemble 0x4b1be0
        Dump of assembler code for function _ZThn16_N7Class_C2fbEv:
                0x00000000004b1be0 <+0>:tsub    $0x10,%rcx
                0x00000000004b1be4 <+4>:tjmpq   0x4213f0 <Class_C::fb()>
     // 本来%rcx == ref_B即&c + 0x10
     // %rcx -= 0x10使得%rcx指向了&c
     //然后jmpq到0x4213f0即Class_C:fb()
     //即调用C::fb前,将this从&c+0x10移回了&c
     //很好理解,毕竟调用的是Class_C的fb,那么this必须是&c
     0x0000000000401871  lea    0xb0368(%rip),%rdx        # 0x4b1be0 <_ZThn16_N7Class_C2fbEv> 
    0x0000000000401878  mov    -0x10(%rbp),%rax //ref_B 即 this
    0x000000000040187c  mov    %rax,%rcx //%rcx传参寄存器
    0x000000000040187f  callq  *%rdx
    //temp = ref_B.ib;
    0x0000000000401881  mov    -0x10(%rbp),%rax
    0x0000000000401885  mov    0x8(%rax),%eax
    0x0000000000401888  mov    %eax,-0x1c(%rbp)
    //pc->fc();
    0x000000000040188b  mov    -0x18(%rbp),%rax
    0x000000000040188f  mov    (%rax),%rax
    0x0000000000401892  add    $0x10,%rax //fc 
    0x0000000000401896  mov    (%rax),%rdx
    0x0000000000401899  mov    -0x18(%rbp),%rax
    0x000000000040189d  mov    %rax,%rcx
    0x00000000004018a0  callq  *%rdx
    //temp = pc->ic
    0x00000000004018a2  mov    -0x18(%rbp),%rax
    0x00000000004018a6  mov    0x1c(%rax),%eax
    0x00000000004018a9  mov    %eax,-0x1c(%rbp)
    

    上面调用ref_B.fb()时,其实编译器做了一些优化,如果我们把代码改成:

    void func(Class_B &ref_B){
        ref_B.fb();
    }
    
    int main(int argc, char const *argv[])
    {
    
        Class_B b;
        Class_C c;
        func(c);
        return 0;
    }
    

    那么汇编中的地址就不是写死的了,而是

    //func(c)
    0x000000000040184f  lea    -0x30(%rbp),%rax
    0x0000000000401853  add    $0x10,%rax
    0x0000000000401857  mov    %rax,%rcx
    0x000000000040185a  callq  0x401800 <func(Class_B&)>
    //func的汇编代码:
    0x000000000040180c  mov    0x10(%rbp),%rax
    0x0000000000401810  mov    (%rax),%rax // 取虚函数表首地址到%rax,在gdb中查看为0x4c2f58
    0x0000000000401813  mov    (%rax),%rax //取虚函数表第一项,在gdb中查看为0x4b1b70 即<_ZThn16_N7Class_C2fbEv>
    0x0000000000401816  mov    0x10(%rbp),%rcx
    0x000000000040181a  callq  *%rax //调用_ZThn16_N7Class_C2fbEv, ZThn16_N7Class_C2fbEv再调用C::fb()
    

    问题: 在多重继承中,每个虚表第一个槽中的type_info是对应base class还是全是derived class的类型? - 果冻虾仁的回答 - 知乎中写道,父类指针调用虚函数时,校准this,使其指向准确的地址,这个操作是通过this - topoffset(虚函数表第一个entry)实现的。但这里查看汇编后,发现是通过将虚函数表中的虚函数替换成一个跳转函数来实现的。哪个是对的呢?

    动态绑定的实现

    所谓动态绑定 ref.f() p->f() 的关键在于引用(指针)与对象绑定的时刻:

    Type &ref = c; Type *p = &c; 
    

    这一刻,一个地址将会赋值给ref(p),而动态绑定完全依赖于这个地址。 比如c的类型为C,而C继承了A,B(就是上面的哪个例子) 当Type为A时,ref = &c 当Type为B时,ref = &c + offset。

    而当编译器碰到p->fb()时,无论p的类型是什么,编译器都只会翻译成这样的一段代码:

    0x000000000040180c  mov    0x10(%rbp),%rax
    0x0000000000401810  mov    (%rax),%rax // 取虚函数表首地址到%rax
    0x0000000000401813  mov    (%rax),%rax //取虚函数表第一项
    0x0000000000401816  mov    0x10(%rbp),%rcx
    0x000000000040181a  callq  *%rax
    

    这段代码就是执行虚函数表中的第一个函数,无论p的类型,虚函数表中填的什么,那就执行什么。所以当我们绑定的时候,p会指向一个正确的虚函数表。

    总的来说,动态绑定由两个部分协作完成: 1. 绑定时刻,将指针p或引用ref指向正确的虚函数表的地址 2. 调用时刻,(*p)[i]访问第i个虚函数 只要p或ref弄对了,那么动态绑定就会访问正确的虚函数。


    总结,假设我们定义了3个类:class A; class B; class C : public A, public B;

    • 此时内存中有3个虚函数表,A, B,C的。C中又内含了一个A的虚函数表和B的虚函数表并重写了虚函数地址。

    参考资料:

    1. 《C++对象模型》
    2. http://www.jeepxie.net/article/439958.html
    展开全文
  • 文/BeauPowerBI星球嘉宾数据分析...模型介绍帕累托法则 在任何组东西中,最重要的只占其中小部分,约20%,其余80%尽管是多数,却是次要的,因此又称二八定律。该法则在企业中可解读为20%的销售来自于80%的...

    文/Beau

    PowerBI星球嘉宾数据分析爱好者,擅长PBI数据分析

    作品链接:http://suo.im/5TqjDi(请复制到浏览器中查看)

    提醒:建议在PC端查看,首次浏览可能反应速度会较慢,请耐心等待。

    一、模型介绍

    帕累托法则    

    在任何一组东西中,最重要的只占其中一小部分,约20%,其余80%尽管是多数,却是次要的,因此又称二八定律。

    该法则在企业中可解读为20%的销售来自于80%的顾客,因此在面向这部分顾客,进行有重点、有针对性的服务。当然在对产品,渠道等多个销售维度分析都具有普适性。在实际销售场景中,可利用此法则快速定位头部客户,主力产品等,从而有效提升销售效率。

    本文模型基于帕累托法则核心要义,结合零售行业数据,利用Power BI进行建模及可视化多级动态展现。

    具体如下图:

    63596b5f0a97e33f1eb76dfa6a5c0842.png

    具体布局及实现功能如下:

    1.切片区 (红框)

    KPI,单位,轴维度,配色方案,层级一。可对各字段进行动态切片选择。

    配色方案切片:仅对帕累托图有效。

    轴维度切片:对帕累托图X轴进行动态切换。

    层级一切片:可对层级一的项目进行选择,实现选择项的相对累计占比动态显示。

    7ab7c29d37342fe3a5f01ff51d410737.gif

    2.数值筛选区(黄框)

    日期,ABC占比,色彩饱和度。

    色彩饱和度同配色方案切片,仅对帕累托图有效。

    0f0f67ded994419721157c567cd452f0.gif

    3.信息提示区(蓝框)

    筛选清除按钮,信息提示按钮,下钻信息按钮。

    筛选清除按钮:一键初始化切片器。

    信息提示按钮:便于读者对模型的解读,对重点信息进行提示。

    下钻信息按钮:对当前是否可下钻进行判断,可通过按钮点击进行下钻跳转。

    38321ca88c8ed49c1e1c9bc50065e8f4.gif

    4.帕累托图表区(绿框)

    矩阵伸缩按钮,视觉对象标头动图工具提示。

    矩阵伸缩按钮:可通过点击实现矩阵表的展开和缩回,搭配帕累托图,数据信息展现更加全面。

    视觉对象标头动图工具提示:对在图表区可以使用的三种下钻方式进行提供动图化的工具提示,能让初次看到的读者快速了解使用方法。

    6e0851704614a18597cdfd872179162e.gif

    今天这篇文章的内容将围绕如何实现多级下钻来进行展开。至于其他细节技巧,在后续文章中会有深度解读。

    二、何为多级帕累托

    图表的多级下钻对于熟悉PBI的小伙伴来说并不陌生,当数据结构为多个层级时,可以通过下钻实现对每个层级的展现分析。

    目前在网上能看到很多关于帕累托可视化以及图表多级下钻的教程,但对于两者的结合,目前却没找到现成的资料和教程,于是心血来潮,想尝试实现多级帕累托,于是便有了此模型。

    三、解决思路

    对于实现多级下钻,总的来说需要做好两个方面的工作:

    1.建立多层级字段表:比如要建立 产品类别--产品子类别的层级关系表,常规维度表一般都会具备这样的层级结构。

    2.建立相应度量值:一般这是实现多级可下钻的关键所在。

    下面我们就对度量值的构建进行重点解读。

    四、具体步骤

    1.建立维度表

    这里我们以产品维度为例,进行多级下钻的展示。维度表如下图所示:

    b9ff54e35f0ac3389b4b0b81d9ea0267.png

    上图可以看到产品表中已存在产品类别-产品子类别的层级结构。

    那么对于轴下钻以及KPI度量值已无问题,那么接下来重点就是累计占比度量值的构造。

    2.构造累计占比度量值

    首先我们理一下构造逻辑:

    • 当前层级为一层级(产品类别)时,显示一层级各项目的累计占比,同时可以进行切片筛选。

    • 当前层级为二层级(产品子类别)时,显示二层级各项目的累计占比,同时可以进行切片筛选。

    很显然,根据上面的逻辑,这里首先要对当前所处层级进行判断,然后进行相应计算即可,那么这里需要用到一个关键函数-ISINSCOPE,可以利用此函数判断当前层级。

    那么累计占比度量值可以顺利写出:

    ----------

    累计占比(%) =VAR cur = [KPI]VAR grand_leve1 =    CALCULATE( [KPI], FILTER ( ALLSELECTED ( '产品'[产品类别] ), [KPI] >= cur ) )VAR grand_leve2 =    CALCULATE( [KPI], FILTER ( ALLSELECTED ( '产品'[产品子类别] ), [KPI] >= cur ) )VAR is_leve1 =    ISINSCOPE( '产品'[产品类别] )VAR is_leve2 =    ISINSCOPE( '产品'[产品子类别] )RETURN    SWITCH(        TRUE(),        is_leve1&& NOT ( is_leve2 ), DIVIDE ( grand_leve1, CALCULATE ( [KPI],ALLSELECTED ( '产品'[产品类别] ) ) ),        DIVIDE( grand_leve2, CALCULATE ( [KPI], ALLSELECTED ( '产品'[产品子类别] ) ) )    )

     ----------

    以上DAX中要注意ALLSELECTED的使用,这里是能够实现对层级项进行切片动态显示相对累计占比的关键。至于ABC分类配色度量等度量采大公号里有相关文章,不再赘述。

    接下来的步骤就很简单了,创建折线和堆积柱形图,拉入相关字段值,这样一个多级可下钻的帕累托图就呈现在面前了。

    44363a6315a7e81a39970eb42989e365.gif

    五、说在最后

    其实从本质上看,实现多级下钻的关键在于累计占比度量的构建,那么从本文中的方法可以发散扩展到其他任意可视化对象的下钻,其逻辑是相同的。

    看到这里,可能有小伙伴会问,能否实现在下钻到第二层级也可以进行类似第一层级的切片筛选?能否实现三级下钻?

    关于以上及更多的问题,你需要做的就是点击篇头模型链接,进去慢慢品,慢慢发现,可以的话也尝试做一下,你的收获会更大。

    正像文章开头所说,今天这篇文章的内容将主要围绕如何实现多级下钻来进行展开。关于模型更多的细节和技巧处理,如大家感兴趣后期会继续写文进行深度讲解。

    关于帕累托,关于多级下钻以及更多好的建议,欢迎小伙伴们与我一起交流。

    -精彩推荐-

    4f0b937022097225fedb38f5bb8151a5.pnga1c358043a07674d49523bb84fad1f51.pngd8dd5046f52db19ca0bc5a9cbfd19162.png如果你刚开始学习Power BI,可在微信公众号后台回复"PowerBI",获取《七天入门PowerBI》电子书,轻松上手。成为PowerBI星球会员,问题随时答疑,更多资源分享a862f1a450dd583b96f4abb83989b145.png添加微信:PowerBI001,进入学习交流群
    展开全文
  • 数学模型之灰色模型

    千次阅读 2016-07-13 15:24:50
    1 作为个发展变化的系统,关联度分析实际上是动态过程发展态势的量化比较分析。 发展态势比较:系统各时期的有关统计数据的几何关系的比较。 关联度分析可以确定个系统的目标层与因素层之间的关系大小。 2 优势...

    灰色系统理论

    1 作为一个发展变化的系统,关联度分析实际上是动态过程发展态势的量化比较分析。

    发展态势比较:系统各时期的有关统计数据的几何关系的比较。

    关联度分析可以确定一个系统的目标层与因素层之间的关系大小。

    2 优势分析

      多个参考数列和比较数列,得到关联矩阵,可以确定子因素对母因素(参考数列)的影响程度。

    3 生成数

      寻找随机变量数列之间的关系。

    4 灰色模型

    5 灰色预测

      通过原始数据的处理和灰色模型的建立,发现和掌握系统发展规律,对系统的未来状态做出科学的定量预测。GM(1,1)模型,灰色马尔科夫模型。道路交通事故的Verhulst模型。

    6 灰色决策模型


    7 模型检验

      残差合格模型

      关联度合格模型

      均方差合格模型

      小误差概率合格模型

    实例:

      道路交通安全系统是一个灰色系统。

    展开全文
  • 主题演化是网络舆情分析的重要内容之一,为了把握关于新疆的舆情动态,该文从主题热度变化、内容变化及关键词等多方面进行了研究。该文首先抓取了2013年1月到2015年12月互联网中关于新疆暴恐事件的新闻,并以此作为数据...
  • 片段缓存机制是加速动态网页分发的有效解决方案之一,但是实施片段缓存需要有效的共享片段检测机制。针对这种情况,提出一种高效的共享片段检测算法,并介绍了基于片段缓存的动态网页传送模型。该模型能够自动识别...
  • 信息可视化(绘图)是数据分析中最重要的工作之一,他可能是探索过程的一部分。它可以协助找出异常值、必要的数据转接,得出有关模型的idea。同时实现一个可交互的数据可视化也是工作的最终目标。python有许多库可以...
  • 论文研究-核电项目暂停审批与我国减排目标的实现:基于CGE模型分析.pdf, 受日本核泄漏事件影响,国务院提出在核安全规划批准前,暂停审批核电项目.作为我国重要的清洁...
  • 数学建模时间序列模型及其应用

    千次阅读 多人点赞 2020-08-12 21:38:42
    摘要 时间序列模型就是将预测对象按照时间顺序排列起来...优点是简单易行,便于掌握,能够充分运用原时间序列的各项数据,计算速度快,对模型参数有动态确定的能力,精度较好,采用组合的时间序列或者把时间序列和其他模型
  • 为了编写出个“好”的程序,必须分析待处理的对象的特性以及各处理对象之间存在的关系。 一般来说,用计算机解决个问题时,大致需要经过以下几个步骤: (1)首先要从具体问题抽象出个适当的数学模型。 (2)...
  • 信息可视化(也叫绘图)是数据分析中最重要的工作之一。它可能是探索过 程的一部分,例如,帮助我们找出异常值、必要的数据转换、得出有关模型 的idea等。另外,做一个可交互的数据可视化也许是工作的最终目标。Python...
  • 数据仓库OLAP

    2012-02-20 09:32:04
    联机分析(OLAP)是由关系数据库父E.F.Codd于1993年提出的数据动态分析模型,它允许以种称为多维数据集的多维结构访问来自商业数据源的经过聚合和组织整理的数据。以此为标准,OLAP作为单独的类产品同联机...
  • 信息可视化(也叫绘图)是数据分析中最重要的工作之一。它可能是探索过程的一部分,例如,帮助我们找出异常值、必要的数据转换、得出有关模型的idea等。另外,做一个可交互的数据可视化也许是工作的最终目标。Python...
  • 论文链接:http://www.cqvip.com/qk/92026b/200401/9157745.html引用量:67摘 要 :时间序列分析方法是经济领域研究的主要工具之一 .它用合适的模型描述历史...文中通过ARMA模型分析时间序列的随机性 和平稳性 ,以...
  • 信息可视化(也叫绘图)是数据分析中最重要的工作之一。它可能是探索过程的一部分,例如,帮助我们找出异常值、必要的数据转换、得出有关模型的idea等。另外,做一个可交互的数据可视化也许是工作的最终目标。Python...
  • 信息可视化(也叫绘图)是数据分析中最重要的工作之一。它可能是探索过程的一部分,例如,帮助我们找出异常值、必要的数据转换、得出有关模型的idea等。另外,做一个可交互的数据可视化也许是工作的最终目标。Python...
  • 时间序列分析大致可分成三大部分,分别是描述过去、分析规律和预测未来,本讲将主要介绍时间序列分析中常用的三种模型:季节分解、指数平滑方法和ARIMA模型,并将结合spss软件对时间序列数据进行建模。 组成要素:1...
  • 信息可视化(也叫绘图)是数据分析中最重要的工作之一。它可能是探索过程的一部分,例如,帮助我们找出异常值、必要的数据转换、得出有关模型的idea等。另外,做一个可交互的数据可视化也许是工作的最终目标。Python有...
  • 、计算(数据结构与算法研究的对象和目标) 二、计算模型 一般情况下我们主要考虑时间复杂度 三、大O记号 常见时间复杂度的分级 四、算法分析 级数 级数在循环中的应用 算法分析示例 五、迭代与递归 减...
  • 隐马尔可夫模型(Hidden Markov Model,HMM)是结构最简单的动态贝叶斯网,这是种著名的有向图模型,主要用于时序数据建模(语音识别、自然语言处理等)。 本文深度分析总结模型的原理,并给出模型python的实现...
  • 任务50: Excel抓取网页数据之搭建简单网站服务器及新建简单表格页面 任务51: 利用Excel自带功能抓取网页数据 任务52: VBA编程实现抓取网页源代码 任务53: VBA编程实现获取网页表格写入数据表 第6章: MySQL...
  • 继续学习人民邮电出版的《机器学习实践指南》,第7章股市预测,模型直接拿来用于上证指数,动态时间...本文仅用于python数据分析之DataFrame操作学习! 、指数搜索 import tushare as ts ts.get_index() ...
  •  联机分析(OLAP)是由关系数据库父E.F.Codd于1993年提出的数据动态分析模型,它允许以种称为多维数据集的多维结构访问来自商业数据源的经过聚合和组织整理的数据。以此为标准,OLAP作为单独的类产品同...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 427
精华内容 170
关键字:

动态模型分析数据之一是