一种精细化计算设备状态的方法

在面板/半导体行业领域,设备状态的管理一般包含以下两个层面:

1,设备状态管理的层级:一般分为3个层级。主设备(EQP)、一级子单元(Unit),二级子单元(SubUnit)。

2,设备状态的定义:RUN(运行)、IDLE(空闲)、DOWN(宕机)、PM(保养)、ENG(调机)、TEST(测试)、JC(换线)等状态。

这两大方面是设备稼动率、OEE等指标计算的基础。行业内的各公司在这两大基础面的定义相差无几。然而,基于设备状态切换历史,进而计算设备的各项稼动指标的具体逻辑,则不尽然相同。

考虑多腔室类型的设备,借用编程的术语,这些设备具备“并发”能力。举例来说,某设备EQP_MAIN具有两个制程能力相同的UNIT,分别为UNIT1和UNIT2。若UNIT1为DOWN且UNIT2为RUN,此状态持续1小时,此时,无论EQP_MAIN挂RUN还是DOWN,均需要考虑:这1小时并非完整的DOWN或者RUN,而应该折算成RUN 0.5小时和DOWN 0.5小时。

现实世界中的设备层级要远复杂于此例子。但借鉴此思想,对各设备一级单元(Unit)或者二级子单元(SubUnit)进行合理划分,然后考虑不同UNIT状态的组合,并按其对设备状态影响程度,赋予不同的权重因子,则可实现对设备状态精细化的计算。

本文接下来主要描述如何设计算法和程序,来实现这种计算。

首先考虑以下几个要素:

计算时间点的选择:有两种选择,一是预先算好,例如采用ETL的方式。二是实时查询并计算。由于用户要求的应用场景等多种因素限制(例如PM等状态是人为标注的,且存在多次修改备注信息的场景,所以预先算好的方式不适用),本文采用了实时计算的方式。

查询性能的预估分析:由于设备的状态切换历史非常频繁,所以表中的数据量非常庞大。假如用户的查询范围是2个月内全部设备,则查询原始数据,然后再进行各种复杂计算,可以想象,要想快速计算出结果,必然是一个相当大的挑战。

系统架构的限制:不幸的是,面板行业/半导体行业的报表系统架构,基本上是采用集中式架构。此需求根本无法应用分布式计算框架。只能通过精心设计程序和算法,充分压榨oracle服务器和应用服务器,实现大数据量的快速计算。

计算资源的分配:报表采用的WEB架构,所以不可能在本机计算。只能是在DB服务器或者应用服务器上进行计算。以此需求为例,从DB试select 1台设备1个月的原始数据,一共4万笔,大约需要10多秒钟。select 1天,一共1千多笔,则需要300ms。考虑到底层数据是设备状态的原始数据,而计算过程相当复杂,如果把所有的逻辑计算放在DB服务器,对用户而言,查询的响应时间必然很慢。所以要合理平衡DB服务器和应用服务器,分配合适的计算任务。

进行以上要素分析和试验之后,采用以下设计:

1,采用分治法。在oracle端,将原始数据按设备按天切割(切割点为每天的08:00),然后发给应用服务器。应用服务器采用java/C#等编程语言,对按天切割后的数据,进行复杂逻辑运算。然后应用服务器对子计算任务的结果进行合并,作为最终结果。

2,虽然有多个子计算任务,但由于DB服务器和应用器同时并发,所以整体的查询响应时间,优于仅在oracle 上运算的方案。

3,状态组合的逻辑、各单元的权重等信息,设计配置表,由用户来维护。维护表需要包含以下信息:

  • 设备单元信息。定义了各个设备、各级子单元等信息。
  • 设备的状态关键单元。定义每个设备要查看哪些关键单元。
  • 设备的状态组合与状态权重的对应关系。定义关键单元的每种状态组合下,其状态权重。

接下来进行按天查询指定设备算法的设计。

1,应用服务器同时请求查询原始数据表和配置信息表。

private DataTable QueryRawData(DateTime periodDate, string machineName)
{
    var sql = $@"
                select a.machinename as {RawDataTable.MACHINE_NAME}, a.timekey as {RawDataTable.EVENT_TIME},
                        a.oldmachinestatename as {RawDataTable.PREV_STATUS}, a.machinestatename as {RawDataTable.CUR_STATUS}
                from CT_MACHINEHISTORY a
                where 1=1
                and a.machinename like '{machineName}%'
                and timekey>='{periodDate.ToString("yyyyMMddHH")}'
                and timekey<'{periodDate.AddDays(1).ToString("yyyyMMddHH")}'
                order by a.machinename, a.timekey
                ";

    var dtRaw = ConnectionKey.MESDBDG.Query(sql);
    return dtRaw;
}

private DataTable QueryEqpSpec(string machineName)
{
    var sql = $@"
                select a.machinename as {SpecDataTable.MACHINE_NAME}, 
                    a.detailmachinetype as detail_machine_type
                from MACHINESPEC a
                where 1=1
                and a.machinename like '{machineName}%'
                order by a.machinename";

    var dt = ConnectionKey.MESDBDG.Query(sql);
    return dt;
}

private DataTable QueryEqpStatusFactorSpec(string machineName)
{
    var sql = $@"
                select a.MACHINE_NAME as {EqpStatusFactorSpecTable.MACHINE_NAME}, 
                    a.KEY_UNIT_LIST as {EqpStatusFactorSpecTable.KEY_UNIT_LIST},
                    a.RATIO_LIST as {EqpStatusFactorSpecTable.RATIO_LIST},
                    REGEXP_REPLACE(REGEXP_REPLACE(a.UNIT_STATUS_PATTERN,'\*','.'),',','') as {EqpStatusFactorSpecTable.UNIT_STATUS_PATTERN},
                    a.DEFINED_MACHINE_STATUS as {EqpStatusFactorSpecTable.DEFINED_MACHINE_STATUS}
                from Eqp_Status_Factor_Spec a
                where 1=1
                and a.MACHINE_NAME = '{machineName}'";

    var dt = ConnectionKey.RPTDB.Query(sql);
    return dt;
}

注:配置表有2个。分别在不同的DB。原因是其中一个DB为readonly,不能建表。而已有的配置信息不够全,需要完善。

2,找出该天中“缺少”的单元,并补出它在当天的状态。由于每个设备包含多个单元,而有些单元可能在该天无任何状态变化,则这样原始数据表中无此单元的记录。但是状态计算时,需要考虑到每个单元,所以需要“补偿”。基本思想就是,通过配置表,找到完整的单元集合。然后减去有实际抓取出来的单元集合,得到“缺少”的单元集合。然后将“缺少”的每个单元,找出其离指定最近的前一笔记录,该笔记录的设备单元状态,作为该单元在指定天起点和终点的状态(全天维持状态不变)。

要说明的是,如果存在多个“缺少”的单元,假如采用每笔问询一次oracle,则会大大降低整体查询效能。所以,这里优化设计,仅查询1次。

private DataTable CompensateMissedHistory(DateTime periodDate, DataTable dtEqpSpec, DataTable dtRaw)
{
    var dt1 = dtEqpSpec.SelectDistinct(SpecDataTable.MACHINE_NAME);
    var dt2 = dtRaw.SelectDistinct(RawDataTable.MACHINE_NAME);
    var dt3 = dt1.Except(dt2);
    if (dt3.Rows.Count > 0)
    {
        var dt4 = QueryPrevRawData(periodDate, dt3.GetColumnData<string>(0));
        var dt5 = dt4.Clone();
        foreach (DataRow dr in dt4.Rows)
        {
            dt5.Rows.Add(dr[0], periodDate.ToString("yyyyMMddHHmmssffffff"), dr[3], dr[3]);
            dt5.Rows.Add(dr[0], periodDate.AddDays(1).ToString("yyyyMMddHHmmssffffff"), dr[3], dr[3]);
        }

        return dt5;
    }

    return dt3;
}

private DataTable QueryPrevRawData(DateTime periodDate, IEnumerable<string> machineNames)
{
    var sqlFormat = @"
                select * from
                (
                    select a.machinename as {0}, a.timekey as {1},
                        a.oldmachinestatename as prev_status, a.machinestatename as cur_status
                    from CT_MACHINEHISTORY a
                    where 1=1
                    and a.machinename = '{2}'
                    and timekey<'{3}'
                    and rownum<=1 
                    order by a.machinename, a.timekey desc
                )
                ";

    var sql = new StringBuilder();
    var uninVerb = " union ";
    foreach (var machineName in machineNames)
    {
        sql.AppendFormat(sqlFormat, RawDataTable.MACHINE_NAME, RawDataTable.EVENT_TIME, machineName, periodDate.ToString("yyyyMMddHH"));
        sql.Append(uninVerb);
    }

    sql = sql.Remove(sql.Length - uninVerb.Length, uninVerb.Length);

    var dt = ConnectionKey.MESDBDG.Query(sql);
    return dt;
}

3,将各单元按每天的时间切割点进行“对齐”。各单元在该天的首笔状态切换,不会刚好发生在切割点时间。所以需要补偿出从时间切割点到首笔状态变化之间的状态。同理,各单元在该天的末笔状态切换,也不会刚好发生在第二天的切割点时间。所以需要补偿出末笔到第二天切割点之间的状态。

private DataTable CompensateDateTimeBoundary(DateTime periodDate, DataTable dtRaw)
{
    var ds = dtRaw.GroupBy(RawDataTable.MACHINE_NAME);
    var startTime = periodDate.ToString("yyyyMMddHHmmssffffff");
    var endTime = periodDate.AddDays(1).ToString("yyyyMMddHHmmssffffff");

    for (var i = 1; i < ds.Tables.Count; i++)
    {
        var dt = ds.Tables[i];
        if (!object.Equals(dt.Rows[0][1], startTime))
        {
            var dr1 = dt.NewRow();
            dr1[0] = dt.Rows[0][0];
            dr1[1] = startTime;
            dr1[3] = dr1[2] = dt.Rows[0][2];
            dt.Rows.InsertAt(dr1, 0);
        }

        if (!object.Equals(dt.Rows[dt.Rows.Count - 1][0], endTime))
        {
            var dr2 = dt.NewRow();
            dr2[0] = dt.Rows[dt.Rows.Count - 1][0];
            dr2[1] = endTime;
            dr2[3] = dr2[2] = dt.Rows[dt.Rows.Count - 1][3];
            dt.Rows.Add(dr2);
        }
    }

    var dtResult = ds.Tables[1].Clone();
    for (var i = 1; i < ds.Tables.Count; i++)
    {
        dtResult = dtResult.UnionAll(ds.Tables[i]);
    }
    return dtResult;
}

4,至此,该天该设备的全部单元的切换历史,就准备完成了。不过进一步分析原始数据,发现有些单元会存在少量的这种情况:下一笔的状态和上一笔的状态相同。所以,为降低该天时间切割的区间数量,减少后续的计算量,可以对这种情况进行优化。也就说,对状态维持不变的多笔记录,"压缩“成1笔记录。

private DataTable CompressRawData(DataTable dtRaw)
{
    var dt = dtRaw.Clone();
    dt.ImportRow(dtRaw.Rows[0]);
    for (var i = 1; i < dtRaw.Rows.Count - 1; i++)
    {
        if (dtRaw.Rows[i][3].ToString() == dtRaw.Rows[i - 1][3].ToString() &&
            //dtRaw.Rows[i][2].ToString() == dtRaw.Rows[i - 1][2].ToString() &&
            dtRaw.Rows[i][0].ToString() == dtRaw.Rows[i - 1][0].ToString())
            continue;

        dt.ImportRow(dtRaw.Rows[i]);
    }
    return dt;
}

5,得到这些数据后,就可以在应用服务器进行开始进行逻辑运算。为根据指定的状态组合组合和权重进行计算,有考虑设计关联查询的方案和类似掩码的方案。关联查询方案的方案理论可行,但是当设备的单元够多时(例如有N个单元),则各单元的可能的状态组合数是7的N次方。计算量非常庞大,实际不可行。采用类似掩码的方案,一番分析下来发现很难实现。首先是每个单元状态有7种,0和1的方案本身就无法代表。如果要扩展,则要判断状态时,会变得非常复杂,基本不可行。综合先来,唯一可行的解法,就是设计正则表达式。这样实现了以尽可能少的行覆盖了全部的状态组合。既方便用户建配置表,又能使程序快速得到权重规则,进而基于规则再进行计算。

考虑到为提高运算效率,分析7种状态,发现首字母各不相同,故分别用首字母代表各个状态。算法简述如下:

  • 首先,将设备单元的实际状态,提取首字母,“浓缩”成一个字符串。这个字符串代表当前设备各个单元的状态组合。
  • 接下来,以上述字符串作为正则表达式的输入,扫描配置表中用户定义的全部状态组合模式,进行正则表达式模式匹配。一旦匹配成功,取出该状态对应的权重计算规则。为方便用户建立和维护配置表,状态组合模式并非全部采用正则表达式语法,故需要在取配置表时做一定的替换。例如,用户建表时,让其输入‘*’代表任意字符,并将各状态以','分隔方便查看。取出来时要转成‘.’,且为了提高匹配效率,去掉了','。
  • 然后,分析权重计算规则,将设备实际的单元状态,回填到规则,生成各个状态的权重系数。权重规则中,是要捕获实际的状态值。这里有两种设计法。一种是按正则表达式的组捕获方法,来设计规则输入模式;另一种,采用字符串占位符,然后编写解析和回填方法。为提高程序运行效率且便于用户理解,这里采用了第二种设计。
  • 再下来,对已生成的各状态权重系数进行同类求和,得到最终结果。
public DataTable BuildResult(DateTime periodDate, string machineName)
{
    var dtRaw = QueryRawData(periodDate, machineName);
    var dtSpec = QueryEqpSpec(machineName);
    var dtFactorSpec = QueryEqpStatusFactorSpec(machineName);

    var dtMissed = CompensateMissedHistory(periodDate, dtSpec, dtRaw);
    var dtRawCompensated = CompensateDateTimeBoundary(periodDate, dtRaw);
    var dtRawComplete = dtRawCompensated.UnionAll(dtMissed);
    var dtRawCompressed = CompressRawData(dtRawComplete);

    var dtDateTimePoints = dtRawComplete.SelectDistinct(RawDataTable.EVENT_TIME).OrderByAsc(RawDataTable.EVENT_TIME);
    var dtResult = dtDateTimePoints.Copy();

    var ds = dtRawCompressed.GroupBy(RawDataTable.MACHINE_NAME);
    for (var i = 1; i < ds.Tables.Count; i++)
    {
        var dt = ds.Tables[i].SelectFrom(RawDataTable.EVENT_TIME, RawDataTable.CUR_STATUS).
            RenameColumns(RawDataTable.CUR_STATUS, ds.Tables[0].Rows[i - 1][0].ToString());
        dtResult = dtResult.LeftJoin(dt, RawDataTable.EVENT_TIME);
    }

    for (var i = 1; i < dtResult.Rows.Count; i++)
    {
        for (var j = 1; j < dtResult.Columns.Count; j++)
        {
            if (dtResult.Rows[i][j] == DBNull.Value)
            {
                dtResult.Rows[i][j] = dtResult.Rows[i - 1][j];
                dtResult.Rows[i][j] = dtResult.Rows[i - 1][j];
            }
        }
    }

    dtResult = Compute(dtResult, dtFactorSpec);
    return dtResult;
}

上述代码主要是完成原始数据的准备。包含为了方便计算,进行的空值补偿。

核心的计算逻辑如下:

public DataTable Compute(DataTable dtResult, DataTable dtFactorSpec)
{
    var dc = dtResult.AddColumn<string>("CombinedUnitStatus");
    var allStatus = new string[] { "E", "P", "T", "J", "D", "I", "R" };
    dtResult.AddColumns<decimal>(allStatus);

    var keyUnitList = dtFactorSpec.Rows[0][EqpStatusFactorSpecTable.KEY_UNIT_LIST].ToString().Split(',').Select(x => x.Trim()).ToArray();
    dc.Expression = keyUnitList.Select(x => $"SUBSTRING([{x}],1,1)").ToText('+');

    var patternList = dtFactorSpec.SelectFrom(EqpStatusFactorSpecTable.UNIT_STATUS_PATTERN).GetColumnData<string>(0).ToArray();
    var definedMachineStatusList = dtFactorSpec.SelectFrom(EqpStatusFactorSpecTable.DEFINED_MACHINE_STATUS).GetColumnData<string>(0).Select(x => x.Trim()).ToArray();

    for (var i = 0; i < dtResult.Rows.Count; i++)
    {
        var dr = dtResult.Rows[i];
        var combinedStatus = dr["CombinedUnitStatus"].ToString();
        for (var j = 0; j < patternList.Length; j++)
        {
            if (!Regex.IsMatch(combinedStatus, patternList[j]))
                continue;

            var definedStatus = definedMachineStatusList[j];
            var actualStatus = ReplaceWithActual(combinedStatus, definedStatus);
            var dictWeight = SumStatusWeight(actualStatus);

            foreach (var key in dictWeight.Keys)
            {
                dr[key] = dictWeight[key];
            }

            break;
        }
    }

    return dtResult;
}

其中,根据实际值回填规则,生成各个状态的权重系数的方法如下:

private string ReplaceWithActual(string combinedStatus, string definedMachineStatus)
{
    if (!definedMachineStatus.Contains("{"))
        return definedMachineStatus;

    var patterns = definedMachineStatus.Split(',');
    var actualList = new string[patterns.Length];
    for (var i = 0; i < patterns.Length; i++)
    {
        if (!patterns[i].StartsWith("{"))
            continue;

        var index = int.Parse(patterns[i].Substring(1, patterns[i].IndexOf('}') - 1));
        actualList[i] = $@"{combinedStatus[index]}:{patterns[i].Substring(patterns[i].IndexOf(':') + 1)}";
    }

    return actualList.ToText(',');
}

对同类权重系数求和的方法如下:

private Dictionary<string, decimal> SumStatusWeight(string acutalStatus)
{
    var dict = new Dictionary<string, decimal>();
    var actualStatusArray = acutalStatus.Split(',');
    foreach (var status in actualStatusArray)
    {
        var kv = status.Split(':');
        if (!dict.ContainsKey(kv[0]))
            dict.Add(kv[0], Fraction.FromString(kv[1]).ToDecimal());
        else
            dict[kv[0]] += Fraction.FromString(kv[1]).ToDecimal();
    }

    return dict;
}

至此,计算出某个设备在指定天的精细化的状态。后续的展示及更高一层的统计,便可以此为基础数据。

如果要计算多个设备在多天的精细化状态,便可采用多并行编程的方式,进行并行计算。这里不再赘述。

另外要说明的一点,为方便高效开发,程序设计中并未采用linq to dataset的方式进行数据查询和处理,而是自己开发出一套完整的DataTable Extension 流式API,对DataTable进行类似ORACLE式的操作,使得开发更高效,代码更简洁。例如代码中所示的LeftJoin, GroupBy等方法。

完整的程序截图如下。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
公安智能交通一体化管理平台V1.1 产品手册 2014年6月 智能交通一体化管理平台全文共22页,当前为第1页。 智能交通一体化管理平台全文共22页,当前为第1页。 一体化管理平台概述 智能交通一体化管理平台是基于对整个城市交通管理的总体规划和顶层设计而研发的,其依据城市智能交通业务发展的需要,深入探索公安交通管理信息化建设的新理念、新思路、新技术、新方法,并通过融合计算机、通讯、电子、网络、图像、卫星定位、GIS、云存储、大数据处理等多种技术,进行全局系统性的设计,同时制定相应的交通管控业务、数据处理和系统集成规范,为城市交通基础管控、指挥调度、缉查布控、辅助决策提供稳健的管控管理支撑,也为最终实现城市人、车、路、环境一体化和谐的城市交通运行,为智慧城市的建设提供强有力保障。 一体化管理平台V1.1版依据业务职能属性划分为四大子平台,由12大系统模块组成。 智能交通一体化管理平台全文共22页,当前为第2页。 图1-智能交通一体化管理平台主界面 智能交通一体化管理平台全文共22页,当前为第2页。 指挥调度子平台 2.1 子平台概述 该子平台在交通各个基础子系统的基础上,对多种的交通信息进行汇集、分析和处理,实现对各种交通突发事件的调度处理。能够增强指挥中心对控制区域内日常交通流、事件的监视,在重大交通事故和重大灾害事故情况下,能够实现对交通的宏观调控、指挥调度和处置突发事件起到快速反应、快速作战指挥的目标。 2.2子平台系统 2.2.1警务监管系统 图2-警务监管主界面 2.2.1.1 系统概述 智能交通一体化管理平台全文共22页,当前为第3页。智能交通指挥系统的核心理念是:"扁平化指挥,精细化管理"。警务监管系统是实现这一理念的重要抓手。只有实现对警员勤务的精细化管理、精准性定位,才能在扁平化处警时有的放矢、准确无误。"十二五"期间一是要与各指挥中心建设同步实施;二是要建立相应的管理制度,确保新的勤务管理模式能够落实到位。 智能交通一体化管理平台全文共22页,当前为第3页。 统一开发警务监管系统软件,以支队为单位进行部署。警务管理考核以业务工作量化考核为主,以工作成效主观评定为辅,配合执法质量考评全程考、监察监督全面考,结合业务能力提升、队伍管理提升、宣传教育工作等的计划任务评定,再辅以年度职责、能力、表现、态度、心态的非量化评估相结合进行360度全方位综合评定,实现对民警及基层领导的全面绩效评价及考核,为公安部门管理工作提供客观科学的依据。 2.2.1.2 系统功能 值班一览 交警各机构各执勤岗位在当天排班情况,界面中动态展示,直观清晰。 值班管理 将交警各单位警员的勤务、人事基本情况、执勤装备情况进行整合,通过值班和勤务基本信息的采集录入,实现自动排班。 执勤管理 根据执勤岗位信息配置中的人员信息进行排班,可按岗位配置信息排班、按前一周信息和按前两周信息三种方式排班能够显示警员当前的任务状态;通过GIS实时显示警员的当前岗位。 岗位管理 值班值勤岗位信息的维护。 请假管理 请销假信息维护。 警务态势 实时显示警员、警车的执勤位置信息以及查看历史移动轨迹。 智能交通一体化管理平台全文共22页,当前为第4页。人员考核 智能交通一体化管理平台全文共22页,当前为第4页。 警员的勤务考核及事件考核 考核项相关指标配置 2.2.2智能预案系统 图3-智能预案系统 2.2.2.1系统概述 智能预案管理系统的预案来源通常是以往各种类型案情处理经验的总结,或者是一些既定的法律法规所约束的行为。指挥员的指挥调度以事件为起点,通过判断案件、事件的程度及类型来决定是否调用预案来启动预案系统。通过对预案系统的调用,可针对相关案件、事件的不同分类来查询预案库中现有的预案数据,一旦查询到相应的预案信息,指挥员可针对预案提供的处理措施及方法下达指挥调度命令。图形化的预案可以形象的帮助处理突发事件,极大的提高调度和处理速度。也可以给警员处理事件提供参考与指导。 预案信息来源于人工录入、系统生成及典型案例抽象形成,预案的确立过程 主要包括以下部分:预案分析、预案编制、预案审批、 案确立。 智能交通一体化管理平台全文共22页,当前为第5页。 智能交通一体化管理平台全文共22页,当前为第5页。 2.2.2.3系统功能 预案编制 分类编制预案信息,包括:周期性严重堵车预案、突发事件预案、施工占道预案、交通事故预案、恶劣天气处置预案、堵截预案、大型灾害事故处置预案、应急救援预案、大型活动预案等 预案审核 对相关预案进行审核。 预案维护 预案信息的更新维护等。 2.2.3警情调度系统 图4-警情调度系统主界面 2.2.3.1系统概述 智能交通一体化管理平台全文共22页,当前为第6页。 根据警情级别,对报警点周围的视频信息进行联动,结合采集的各类静、动态信息、事件
### 回答1: 效表(Pivot table)是一种数据分析工具,它可以将复杂的数据进行汇总、分类和排序,使得用户可以更加直观和方便地分析数据。效表通常用于计算分组频率、交叉分析、对比分析等数据分析场景,可以帮助用户快速了解数据的整体情况和特征。 但是,效表并不是用于计算分组频率的特殊透视表,它可以完成更多的数据分析任务。同样,计算分组频率也不一定非要使用效表,可以使用其他数据分析工具或编程语言实现。 ### 回答2: 效表是一种特殊的透视表,主要用于计算分组频率。透视表是一种数据分析工具,通过对数据的透视操作来实现数据的汇总和分析。而在透视表的基础上,效表则是一种更为高级和精细化的分析工具。 效表主要适用于对大量数据进行统计和分组频率的计算。它可以将原始数据按照指定的字段进行分组,并以表格的形式展示出来。每个分组显示了该分组的频数和频率,能够很直观地展示数据的分布状况。 在效表中,我们可以根据需要选择分组字段和计算字段,对数据进行更为灵活的分析。我们可以根据特定的分类字段,如年龄、性别、地区等对数据进行分组统计,并计算各组的频数和频率。这样的分析能够帮助我们更好地了解数据的分布特征,发现数据中的规律和差异。 除了分组频率的计算,效表还能够进行一些其他的分析操作,如交叉分析、排序、筛选等。通过这些操作,可以进一步深入挖掘数据中的信息和规律,为我们的决策提供更为准确和全面的参考依据。 综上所述,效表是一种特殊的透视表,主要用于计算分组频率。它能够帮助我们对大量数据进行统计和分析,以便更好地理解数据的分布特征,并为决策提供参考依据。 ### 回答3: 效表,也称为交叉表或列联表,是一种特殊的透视表格,用于计算分组频率。 效表的主要作用是对两个或多个变量之间的关联关系进行分析。它通过对数据进行交叉分类,将变量在各个分类下的频率进行统计,从而提取出变量之间的关系,并得出相应的频数、频率、百分比等统计指标。 通常,效表的构建需要确定一个自变量和一个因变量,其中自变量用于将数据进行分组,而因变量则用于统计频率。自变量可以是任意离散型变量,例如性别、年龄段、地区等,而因变量通常表示某种类别或状态,例如购买与否、满意度等。 通过效表的分析,我们可以直观地了解自变量和因变量之间的关系以及各个类别的频率分布情况。例如,我们可以通过分析性别与购买与否的效表,得出不同性别的购买比例,进而了解性别对购买行为的影响。 在实际应用中,效表经常用于市场调研、社会调查、医学研究等领域。它能够帮助研究者更好地理解数据,发现变量之间的关系,从而为决策提供科学依据。 总之,效表是一种特殊的透视表,主要用于计算分组频率。通过效表分析,我们可以了解变量之间的关系以及各个分组的频率分布情况,从而为决策提供支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值