罗兰谈MATLAB的艺术

将想法转化为MATLAB

请注意

罗兰谈MATLAB的艺术已退役,不会更新。

对表中的数据组进行计算的方法

今天我想介绍一位客座博主Stephen Doe,他在MathWorks的MATLAB文档团队工作。Stephen将讨论分组数据的不同方法,并在这些组上执行计算,使用

内容

创建表

表是面向列数据的方便容器。表中的变量可以具有不同的数据类型,但必须具有相同的行数。可以按行、变量或变量名访问表数据。您可以在表变量中指定组,以便对这些组执行计算。今天,我将展示几种将函数应用于表中的组的不同方法。

首先,让我们创建一个表。方法创建表表格函数,导入工具,或readtable函数。我要用readtable从MATLAB附带的示例文件中读取数据。该文件outages.csv包含了美国12年间电力中断的模拟数据。阅读表格。要显示前五行,请使用表索引。

T =可读的(“outages.csv”“格式”' % C % D % f % f % D % C ');: T (1:5)
ans = 5×6 table区域OutageTime损失客户恢复时间原因_________ ________________ ________________ ________________ _______________西南2002-02-01 12:18 458.98 1.8202e+06 2002-02-07 16:50冬季风暴东南2003-01-23 00:49 530.14 2.1204e+05 NaT冬季风暴东南2003-02-07 21:15 289.4 1.4294e+05 2003-02-07 08:14冬季风暴西部2004-04-06 05:44 434.81 3.4037e+05 2004-04-06 06:18 186.44 2.1275e+05 2002-03-18 23:23严重风暴

文件中有六列。因为我想指定表变量的数据类型,所以我使用格式名称-值对参数。T有两个类别变量(用% C),两个datetime变量(% D)和两个数值变量(% f).

对每个数值变量进行计算

一旦数据在表中,就可以对不同的表变量执行计算。一种方法是使用点表示法按名称引用表变量并执行计算。计算受断电影响的客户总数总和函数,省略任何可能存在的值T.Customers

totalCustomers = sum(T。的客户,“omitnan”
totalCustomers = 1.903e+08

方法将函数应用于每个表变量varfun函数。varfun对于应用函数并在另一个表中返回结果特别有用。

但是,您可能希望仅将函数应用于特定类型的变量。属性指定变量的类型vartype函数。这里我要下标T对于数值变量,并计算每个变量的平均值。因为变量有一些values,我要换行的意思是在匿名函数中,这样我就可以使用“omitnan”国旗。

T2 = T(:,vartype(“数字”));Omean = @(x) mean(x,“omitnan”);均值= varfun(均值,T2)
意味着= 1×2表Fun_Loss Fun_Customers  ________ _____________ 563.89 - 1.6693 e + 05

对数值变量中的组进行计算

该表的一个更有趣的视图是对数据进行分组,并开始寻找分组之间的差异。例如,东北和西南地区的平均功率损失有什么不同?

要回答这个问题,首先可以指定一个或多个表变量为分组变量.分组变量定义将其他表变量分割到的组。然后,可以对每个表变量和结果中的每个组应用一个函数。有关分组变量的更多信息,请参见分组变量以分割数据

属性可以对变量进行分组varfun函数。指定地区作为本表中的分组变量。它是一个分类变量,因此用作分组变量特别方便。指定损失而且客户作为输入变量,按区域计算这两个变量的平均值。我要用同样的omean函数。

meanByRegion = varfun(均值,T,“GroupingVariables”“地区”...“数据源”,{“损失”“客户”})
meanByRegion = 5×4 table Region GroupCount Fun_Loss Fun_Customers _________ __________ ________ _____________ MidWest 142 1137.7 2.4015e+05 NorthEast 557 551.65 1.4917e+05 SouthEast 389 495.35 1.6776e+05 SouthWest 26 493.88 2.6975e+05 West 354 433.37 1.5201e+05

对表变量中的数据应用分组变量的另一种方法是使用accumarray函数。如果我转换T.Region到数值数组,并提取T.LossT,然后我可以计算每个区域的平均功率损失accumarray,就像我做的那样varfun

regions = double(T.Region);A = accumarray(区域,T.Loss,[], mean)
A = 1137.7 551.65 495.35 493.88 433.37

accumarray对数组进行操作。所以要使用accumarray对于表变量,必须从表中提取它。此外,分组变量必须是数字,输出参数是一个数组,而不是一个表。你可以用accumarray对于表变量,它缺乏许多方便varfun提供了。

可以使用指定多个分组变量varfun.例如,我将指定地区而且导致作为变量分组。这些群体被定义为区域和原因的组合。

meanByRegionAndCause = varfun(均值,T,“GroupingVariables”,{“地区”“原因”},...“数据源”,{“损失”“客户”});: meanByRegionAndCause (1:5)
ans = 5×5 table区域原因GroupCount Fun_Loss Fun_Customers _______ ________________ __________ ________ _____________中西部攻击12 0 0中西部能源紧急事件19 536.09 57603中西部设备故障9 343.37 29704中西部强风暴31 1055.7 4.3584e+05中西部雷暴32 941.07 1.3301e+05

多个变量作为函数的输入参数

另一个简单的计算方法是按地区计算停电的平均持续时间。这个计算的基础是OutageTime而且RestorationTime表变量。

你可能会想用varfun对于这个计算也是如此。困难在于varfun将函数分别应用于每个表变量。但是这个计算需要两个变量。换句话说,我们希望应用一个需要两个输入参数的函数。

解决方法是使用rowfun函数。与rowfun时,所有表变量都作为输入参数。如果表有N变量,那么你应用的函数必须接受N输入参数。

为了执行这个计算,我将从定义一个匿名函数开始,该函数用一个输入参数减去另一个输入参数,然后计算平均值。然后我将按地区计算平均停电持续时间rowfun

meanDiff = @(a,b) mean(abs(a-b),“omitnan”);meanOutageTimes = rowfun(meanDiff,T,“GroupingVariables”“地区”...“数据源”,{“OutageTime”“RestorationTime”})
meanOutageTimes = 5×3 table Region GroupCount Var3 _________ __________ _________ MidWest 142 819:14:44 NorthEast 557 51:02:18 SouthEast 389 40:49:49 SouthWest 26 59:31:07 West 354 673:27:12

请注意,OutageTime而且RestorationTime为日期时间变量。可以使用datetime变量执行算术,就像使用数值变量一样。

要重命名变量,可以访问VariableNames属性,并在那里更改其名称。表包含元数据,例如变量名和描述,在名为属性

meanOutageTimes.Properties.VariableNames {“Var3”} =“mean_OutageTime”;: meanOutageTimes (1:5)
ans = 5×3 table Region GroupCount mean_OutageTime _________ __________ _______________中西部142 819:14:44东北557 51:02:18东南389 40:49:49西南26 59:31:07西部354 673:27:12

在多个计算和表格结果中使用组

varfun而且rowfun适用于对表变量执行相同的计算。但是如果你想计算不同的量呢?例如,您可能想要按地区计算平均功率损失,同时还要计算最小停电持续时间。方法执行计算并将结果制成表格findgroups而且splitapply功能。

这些函数的工作方式略有不同varfun而且rowfun.的findgroups函数返回与指定的分组变量对应的数值索引。作为第二个输出,它还返回一个组表。然后你可以打电话splitapply对变量中的每一组应用一个函数。

例如,我将按地区计算平均电力损失、最小停电时间和受影响的最大客户数量。我将在使用时指定组findgroups.然后我可以在多个调用中使用组splitapply

我还要稍微改变一下,去掉所有带的行或者缺少值。我将使用rmmissing函数来删除这些行,这样我就不必指定“omitnan”在每个函数调用中标记。

T = rmmissing(T);[G,results] = findgroups(T(::“地区”));meanLoss = splitapply(@mean,T.Loss,G);minOutageTime = splitapply(@min,T。RestorationTime- T.OutageTime,G); maxCustomers = splitapply(@max,T.Customers,G)
maxCustomers = 3.295e+06 5.9689e+06 2.2249e+06 1.8202e+06 4.26e+06

的输出splitapply是一个数组。maxCustomers是一个5乘1的数字数组。但是,您可以通过将结果作为变量添加到表中来制作表格结果,第二个输出从findgroups

结果。meanLoss= meanLoss; results.minOutageTime = minOutageTime; results.maxCustomers = maxCustomers
results = 5×4 table Region meanLoss minOutageTime maxCustomers _________ ________ _____________ ____________ MidWest 907.19 00:00:00 3.295e+06 NorthEast 383.86 00:00:00 5.9689e+06 SouthEast 508.34 00:00:00 2.2249e+06 SouthWest 541.66 00:28:00 1.8202e+06 West 429.73 00:00:00 4.26e+06

在高桌子上进行计算

到目前为止,我使用的是一个小到可以装入内存的表。但是,如果有太多的数据,无法全部放入内存中呢?我可能仍然想把它当作一个表,并使用相同的函数。

这可以通过创建一个高表.高表在MATLAB中是一种高数组。高数组和高表知道如何一次读取一个数据块中的数据,执行您想要的计算,然后在最后收集输出。处理高表的语法与处理表的语法非常相似。

有关高数组和高表的更多信息,请参见高大的数组

为了演示这是如何工作的,我将用outages.csv.当然,从一个适合内存的文件中创建一个高表有点愚蠢,但这说明了如何使用一个大得多的表。

而不是打电话readtable那我就先打电话吧数据存储阅读outages.csv到一个数据存储。

然后我会打电话给你ds,从数据存储中创建一个高表。现在我有了一个高表,它的外观和功能都非常类似于我在前面的部分中使用的表。您看到的一个不同之处在于,高表显示为m × 6的表,这表明还不知道行数。

数据存储(“outages.csv”);T =高(ds)
使用“本地”配置文件启动并行池(parpool)…连接2个工人。T = M×6 tall table区域OutageTime Loss Customers RestorationTime Cause ___________ ________________ ________________ ________________ _________________ 'SouthWest' 2002-02-01 12:18 458.98 1.8202e+06 2002-02-07 16:50 'winter storm' '东南' 2003-01-23 00:49 530.14 2.1204e+05 NaT 'winter storm' '东南' 2003-02-07 21:15 289.4 1.4294e+05 2003-02-17 08:14 'winter storm' 'West' 2004-04-06 05:44 434.81 3.4037e+05 2004-04-06 06:10 'equipment fault' 'MidWest' 2002-03-16 06:18 186.44 2.1275e+052002-03-18 23:23 'severe storm' 'West' 2003-06-18 02:49 0 0 2003-06-18 10:54 'attack' 'West' 2004-06-20 14:39 231.29 NaN 2004-06-20 19:16 'equipment fault' 'West' 2002-06-06 19:28 311.86 NaN 2002-06-07 00:51 'equipment fault' : : : : : : : : : : : :

现在我可以用findgroups而且splitapply执行一些与之前相同的计算。再一次,我将的意思是在一个匿名函数中,这样我就可以忽略了值,正如我上面所做的那样。

Omean = @(x) mean(x,“omitnan”);T.Region = category (T.Region);原因=绝对的(原因);G = findgroups(T.Region);meanLoss = splitapply(均值,T.Loss,G);meanCustomers = splitapply(mean,T.Customers,G)
meanCustomers = M×1高双列向量???: :

我们看到的不是输出,而是一串问号。这是什么意思?很简单,我还没有进行任何计算。此时,我只定义了我想在高表上执行的计算。直到I收集结果,通过调用收集函数。的输出收集不是一个高数组,必须适合内存。

meanLoss = gather(meanLoss);meanCustomers = gather(meanCustomers)
使用并行池“本地”评估tall表达式:-通过4中的1:在4秒内完成-通过4中的2:在2秒内完成-通过4中的3:在2秒内完成-通过4中的4:在25秒内完成评估使用并行池“本地”评估tall表达式:-通过1中的1:在2秒内完成评估在5秒内完成的meanCustomers = 2.4015e+05 1.4917e+05 1.6776e+05 2.6975e+05 1.5201e+05

现在让我们把结果制成表格。自meanLoss而且meanCustomers不是高数组,结果不是一张高桌子。添加区域作为另一个表变量。

results = table(meanLoss,meanCustomers) region = unique(T.Region);结果。区域= gather(区域)
结果= 5×2表meanLoss meanCustomers ________ _____________ 1137.7 2.4015e+05 551.65 1.4917e+05 495.35 1.6776e+05 493.88 2.6975e+05 493.88 2.6975e+05 493.37 1.6975 e+05评估高表达使用并列池“本地”:-通过1 / 1:完成1秒评估2秒结果= 5×3表meanLoss meanCustomers区域________ _____________ _________ 1137.7 2.4015e+05中西部551.65 1.4917e+05东北495.35 1.6776e+05东南493.88 2.6975e+05西南433.37 1.5201e+05西部

扭转局面

在这里,我向您展示了几种将数据分组到表中进行计算的方法。总之,您可以使用一个或多个分组变量在其他表变量中指定组。然后可以对表变量中的组应用函数。

应用:

  • 函数赋给单个表变量并返回一个数组,使用accumarray
  • 同一个函数给每个表变量并返回一个表,使用varfun
  • 需要所有表变量作为输入参数并返回一个表的函数,使用rowfun
  • 不同的函数对不同的表变量和结果构建一个表,使用findgroups而且splitapply

你呢?在哪里用表格做过分析accumarrayvarfunrowfunfindgroups而且splitapply也许有帮助?你们有需要高桌子的情况吗?让我们知道在这里




发布与MATLAB®R2017a

|