创建一个新表,该表显示 R 中单个列中两个不同类别之间的百分比变化



我正在尝试学习如何使用R"reshape2"包中的一些函数,特别是dcast。我正在尝试创建一个表,显示两个软件版本的聚合总和(所有文件的一个数据类别的总和除以一个"案例"中的最大"RepNum"(以及两者之间的百分比变化。

以下是我的数据集的外观(示例数据(:

| FileName | Version |  Category | Value | TestNum | RepNum |  Case |
|:--------:|:-------:|:---------:|:-----:|:-------:|:------:|:-----:|
| File1    | 1.0.18  | Category1 |  32.5 |      11 |      1 | Case1 |
| File1    | 1.0.18  | Category1 |  31.5 |      11 |      2 | Case1 |
| File1    | 1.0.18  | Category2 |  32.3 |      11 |      1 | Case1 |
| File1    | 1.0.18  | Category2 |  31.4 |      11 |      2 | Case1 |
| File2    | 1.0.18  | Category1 |  34.6 |      11 |      1 | Case1 |
| File2    | 1.0.18  | Category1 |  34.7 |      11 |      2 | Case1 |
| File2    | 1.0.18  | Category2 |  34.5 |      11 |      1 | Case1 |
| File2    | 1.0.18  | Category2 |  34.6 |      11 |      2 | Case1 |
| File1    | 1.0.21  | Category1 |  31.7 |      12 |      1 | Case1 |
| File1    | 1.0.21  | Category1 |  32.0 |      12 |      2 | Case1 |
| File1    | 1.0.21  | Category2 |  31.5 |      12 |      1 | Case1 |
| File1    | 1.0.21  | Category2 |  32.4 |      12 |      2 | Case1 |
| File2    | 1.0.21  | Category1 |  31.5 |      12 |      1 | Case1 |
| File2    | 1.0.21  | Category1 |  34.6 |      12 |      2 | Case1 |
| File2    | 1.0.21  | Category2 |  31.7 |      12 |      1 | Case1 |
| File2    | 1.0.21  | Category2 |  32.4 |      12 |      2 | Case1 |
| File1    | 1.0.18  | Category1 |  32.0 |      11 |      1 | Case2 |
| File1    | 1.0.18  | Category1 |  34.6 |      11 |      2 | Case2 |
| File1    | 1.0.18  | Category2 |  34.6 |      11 |      1 | Case2 |
| File1    | 1.0.18  | Category2 |  34.7 |      11 |      2 | Case2 |
| File2    | 1.0.18  | Category1 |  32.3 |      11 |      1 | Case2 |
| File2    | 1.0.18  | Category1 |  34.7 |      11 |      2 | Case2 |
| File2    | 1.0.18  | Category2 |  31.4 |      11 |      1 | Case2 |
| File2    | 1.0.18  | Category2 |  32.3 |      11 |      2 | Case2 |
| File1    | 1.0.21  | Category1 |  32.4 |      12 |      1 | Case2 |
| File1    | 1.0.21  | Category1 |  34.7 |      12 |      2 | Case2 |
| File1    | 1.0.21  | Category2 |  31.5 |      12 |      1 | Case2 |
| File1    | 1.0.21  | Category2 |  34.6 |      12 |      2 | Case2 |
| File2    | 1.0.21  | Category1 |  31.7 |      12 |      1 | Case2 |
| File2    | 1.0.21  | Category1 |  31.4 |      12 |      2 | Case2 |
| File2    | 1.0.21  | Category2 |  34.5 |      12 |      1 | Case2 |
| File2    | 1.0.21  | Category2 |  31.5 |      12 |      2 | Case2 |

实际数据集有6个唯一文件,两个以前的"TestNums & Versions",2个唯一类别和4个唯一案例。

利用互联网的魔力,我能够拼凑出一个看起来像这样的表格来满足不同的需求(但代码应该是相似的(:

| FileName |  Category | 1.0.1 | 1.0.2 | PercentChange |
|:--------:|:---------:|:-----:|:-----:|:-------------:|
| File1    | Category1 | 18.19 | 18.18 | -0.0045808520 |
| File1    | Category2 | 18.05 | 18.06 | -0.0005075721 |
| File2    | Category1 | 19.27 | 18.83 | -0.0224913494 |
| File2    | Category2 | 19.13 | 18.69 | -0.0231780146 |
| File3    | Category1 | 26.02 | 26.91 |  0.0342729019 |
| File3    | Category2 | 25.88 | 26.75 |  0.0335598775 |
| File4    | Category1 | 31.28 | 28.70 | -0.0823371327 |
| File4    | Category2 | 31.13 | 28.56 | -0.0826670833 |
| File5    | Category1 | 31.77 | 25.45 |  -01999731215 |
| File5    | Category2 | 31.62 | 25.30 | -0.0117180458 |
| File6    | Category1 | 46.23 | 45.68 | -0.0119578545 |
| File6    | Category2 | 46.08 | 45.53 | -0.0045808520 |

这是创建该表的代码:

vLatest 和 vPrevious 是具有最新和第二个最新版本编号的变量

deviations<-subset(df, df$Version %in% c(vLatest, vPrevious))
deviationsCast<-dcast(df[,1:4], FileName + Category  ~ Version, value.var = "Value", fun.aggregate=mean)
deviationsCast$PercentChange<-(deviationsCast[,dim(deviationsCast)[2]]-deviationsCast[,dim(deviationsCast)[2]-1])/deviationsCast[,dim(deviationsCast)[2]-1]

我真的只是希望有人能帮助我理解 dcast 的语法。偏差的最初生成Cast是我对一切如何协同工作最模糊的地方。我真的想获取它,而不是为文件获取它,以便它是唯一"案例"的每个类别的所有文件的总和,并显示它们之间的百分比变化。

|  Case  |   Measure  | 1.0.18 | 1.0.21 | PercentChange |
|:------:|:----------:|:------:|:------:|:-------------:|
| Case 1 | Category 1 |    110 |    100 |         9.09% |
| Case 2 | Category 1 |     95 |     89 |         9.32% |
| Case 3 | Category 1 |     92 |     84 |         8.70% |
| Case 4 | Category 1 |     83 |     75 |         9.64% |
| Case 1 | Category 2 |    112 |    101 |         9.82% |
| Case 2 | Category 2 |     96 |     89 |         7.29% |
| Case 3 | Category 2 |     94 |     86 |         8.51% |
| Case 4 | Category 2 |     83 |     76 |         8.43% |

注意:舍入和百分号是一个加号,但是一个非常受欢迎的加号

这些数字并不反映正确完成的实际数学运算,只是我放在那里展示的随机数字作为示例。我希望能解释一下我正在努力做的数学。

用于测试的示例数据集

FileName<-rep(c("File1","File2","File3","File4","File5","File6"),times=8,each=6)
Version<-rep(c("1.0.18","1.0.21"),times=4,each=36)
Category<-rep(c("Category1","Category2"),times=48,each=3)
Value<-rpois(n=288,lambda=32)
TestNum<-rep(11:12,times=4,each=36)
RepNum<-rep(1:3,times=96)
Case<-rep(c("Case1","Case2","Case3","Case4"),each=72)
df<-data.frame(FileName,Version,Category,Value,TestNum,RepNum,Case)

值得注意的是,这里的df本质上是上述代码中deviations数据帧(带有 vLatest 和 vPrevious(

编辑:

Flick先生的答案几乎是完美的,但是当我尝试在我的实际数据集中实现它时,我遇到了问题。该问题是由于使用vLatestvPrevious作为我的版本,而不仅仅是编写字符串。这是我用来获取这两个变量的代码

vLatest<-unique(df[df[,"TestNum"] == max(df$TestNum), "Version"])
vPrevious<-unique(df[df[,"TestNum"] == sort(unique(df$TestNum), T)[2], "Version"])

当我尝试这个时:

pc <- function(a,b) (b-a)/a
summary <- df %>% 
group_by(Case, Category, Version) %>% 
summarize(Value=mean(Value)) %>% 
spread(Version, Value) %>% 
mutate(Change=scales::percent(pc(vPrevious,vLatest)))

我收到此错误:Error: non-numeric argument to binary operator

第二次编辑:

我尝试为两个 TestNum 值创建新变量(因为它们可以是数值并且不需要有因子(。

maxTestNum<-max(df$TestNum)
prevTestNum<-sort(unique(df$TestNum), T)[2]

(我不使用"prevTestNum<-maxTestNum-1"的原因是因为有时数据结果中省略了版本(

但是,当我将这两个变量放入代码中时,"更改"列都是相同的值。

使用 OP提供的示例数据集,并通过分析编辑,我相信即使使用 OP 的生产数据集,以下代码也可能产生所需的结果。

我的理解是,OP有一个包含许多测试结果的data.frame,但他只想显示两个最新版本的相对变化。

OP 已请求帮助使用dcast()功能。此功能可从两个包中获得,reshape2data.table。这里data.table版本用于快速和简洁的代码。此外,还使用了forcatsformattable包中的函数。

library(data.table)   # CRAN version 1.10.4 used
# coerce to data.table object
DT <- data.table(df)
# reorder factor levels of Version according to TestNum
DT[, Version := forcats::fct_reorder(Version, TestNum)]
# determine the two most recent Versions
# trick: pick 1st and 2nd entry of the _reversed_ levels
vLatest <- DT[, rev(levels(Version))[1L]]
vPrevious <- DT[, rev(levels(Version))[2L]]
# filter DT, reshape from long to wide format, 
# compute change for the selected columns using get(),
# use formattable package for pretty printing
summary <- dcast(
DT[Version %in% c(vLatest, vPrevious)], 
Case + Category ~ Version, mean, value.var = "Value")[
, PercentChange := formattable::percent(get(vLatest) / get(vPrevious) - 1.0)]
summary
Case  Category   1.0.18   1.0.21 PercentChange
1: Case1 Category1 33.00000 31.94444        -3.20%
2: Case1 Category2 31.83333 31.83333         0.00%
3: Case2 Category1 33.05556 33.61111         1.68%
4: Case2 Category2 30.77778 32.94444         7.04%
5: Case3 Category1 33.16667 31.94444        -3.69%
6: Case3 Category2 33.44444 33.72222         0.83%
7: Case4 Category1 30.83333 34.66667        12.43%
8: Case4 Category2 32.27778 33.44444         3.61%

解释

分拣Version

OP 已经认识到,简单地按字母顺序对Version排序并不能确保正确的顺序。这可以通过以下方式进行

sort(paste0("0.0.", 0:12))
[1] "0.0.0"  "0.0.1"  "0.0.10" "0.0.11" "0.0.12" "0.0.2"  "0.0.3"  "0.0.4"  "0.0.5" 
[10] "0.0.6"  "0.0.7"  "0.0.8"  "0.0.9"

0.0.100.0.2之前的地方.

这一点至关重要,因为默认情况下data.frame()字符变量转换为因子。

幸运的是,TestNumVersion有关。因此,TestNum用于借助forcats包中的fct_reorder()函数对Version的因子水平进行重新排序。

这还可以确保dcast()按适当的顺序创建新列。

通过变量访问列

在表达式中使用vLatest / vPrevious返回错误消息

vLatest/vPrevious 中的错误:二进制运算符的非数字参数

这是意料之中的,因为vLatestsvPrevious包含字符值"1.0.21""1.0.18",或者,它们不能分割。这里的意思是取由vLatestsvPrevious和除法给出名称的列的值。这是通过使用get()来实现的。

格式为百分比

虽然scales::percent()返回字符向量,但formattable::percent()确实返回具有百分比表示的数字向量,即我们仍然能够进行数值计算。

数据

正如OP给出的:

FileName <- rep(c("File1", "File2", "File3", "File4", "File5", "File6"),
times = 8, each = 6)
Version <- rep(c("1.0.18", "1.0.21"), times = 4, each = 36)
Category <- rep(c("Category1", "Category2"), times = 48, each = 3)
Value <- rpois(n = 288, lambda = 32)
TestNum <- rep(11:12, times = 4, each = 36)
RepNum <- rep(1:3, times = 96)
Case <- rep(c("Case1", "Case2", "Case3", "Case4"), each = 72)
df <- data.frame(FileName, Version, Category, Value, TestNum, RepNum, Case)

相关内容

最新更新