重塑比较一个级别

时间:2011-07-21 04:19:00

标签: r plyr reshape

我经常有数据,我希望将一个变量级别的值与所有其他变量级别进行比较。每次我编写代码来执行此操作时,我希望它更容易。以下是问题的一个示例:

假设我想将任何切割的钻石平均成本与最佳切割钻石的平均成本进行比较。为了公平起见,我想分别为每个清晰度做这件事。

让我们检查一下我们是否有足够的数据:

> with(diamonds,table(cut,clarity))
           clarity
cut           I1  SI2  SI1  VS2  VS1 VVS2 VVS1   IF
  Fair       210  466  408  261  170   69   17    9
  Good        96 1081 1560  978  648  286  186   71
  Very Good   84 2100 3240 2591 1775 1235  789  268
  Premium    205 2949 3575 3357 1989  870  616  230
  Ideal      146 2598 4282 5071 3589 2606 2047 1212

好的,在Idea中没有零,所以让我们计算平均值。

> claritycut<-ddply(diamonds,.(clarity,cut),summarize,price=mean(price))
> claritycut
   clarity       cut    price
1       I1      Fair 3703.533
2       I1      Good 3596.635
3       I1 Very Good 4078.226
4       I1   Premium 3947.332
5       I1     Ideal 4335.726
6      SI2      Fair 5173.916
7      SI2      Good 4580.261
8      SI2 Very Good 4988.688
9      SI2   Premium 5545.937
10     SI2     Ideal 4755.953
...

我想要的最终结果是:

   clarity  variable     ratio
1       I1      Fair 0.8541899
2       I1      Good 0.8295348
3       I1 Very Good 0.9406098
4       I1   Premium 0.9104200
5       I1     Ideal 1.0000000
6      SI2      Fair 1.0878822
7      SI2      Good 0.9630586
8      SI2 Very Good 1.0489356
9      SI2   Premium 1.1661043
10     SI2     Ideal 1.0000000
...

但我不确定如何巧妙地做到这一点。这个问题的大部分内容涉及计算的中间步骤 - 分歧。

现在我想计算所有削减与理想的相对价格。这是我期望在计算中途看到的数据框 - 只提取一个切割级别:

> claritycutideal <- join(subset(claritycut,cut!="Ideal"),summarize(subset(claritycut,cut=="Ideal"),Ideal=price,clarity))
> print(claritycutideal)
Joining by: clarity
   clarity       cut    price    Ideal
1       I1      Fair 3703.533 4335.726
2       I1      Good 3596.635 4335.726
3       I1 Very Good 4078.226 4335.726
4       I1   Premium 3947.332 4335.726
5      SI2      Fair 5173.916 4755.953
6      SI2      Good 4580.261 4755.953
7      SI2 Very Good 4988.688 4755.953
8      SI2   Premium 5545.937 4755.953
...

哪个有效,但是编写上述声明非常繁琐,我仍然需要完成计算,再次提到理想名称。

> mutate(claritycutideal,ratio=price/Ideal)

感觉我想要像

这样的东西
> cast(claritycut,clarity~cut)
Using clarity, cut as id variables
  clarity     Fair     Good Very Good  Premium    Ideal
1      I1 3703.533 3596.635  4078.226 3947.332 4335.726
2     SI2 5173.916 4580.261  4988.688 5545.937 4755.953
3     SI1 4208.279 3689.533  3932.391 4455.269 3752.118
4     VS2 4174.724 4262.236  4215.760 4550.331 3284.550
...

这完全不适合平均计算,因为我需要知道计算中所有重铸级别的名称:

我想重铸,但有一种方法可以过滤提取的水平并保持其余部分不受影响,例如:

> cast(claritycut,clarity~cut,subset=cut=="Ideal")

存在,但不保留未过滤的级别。

然后我需要再次融化它,虽然有重铸,但没有重新熔化。

有没有人有一个巧妙的技巧来做到这一点?

或许我正在以完全错误的方式看待这一点 - 边际计算是否为我做了这个?


以下作品完全正确但是很繁琐:

> valuevars=function(x)x[!names(x)%in%attr(x,"idvars")]
> melt(ddply(cast(claritycut,clarity~cut),.(clarity),
             function(x)valuevars(x)/x$Ideal))

3 个答案:

答案 0 :(得分:6)

我不确定这是否足够整洁,但有两个班轮:

# from your code
claritycut <- ddply(diamonds,.(clarity,cut),summarize,price=mean(price))

# 1 do that work
transform(merge(claritycut, subset(claritycut, cut=="Ideal"), by="clarity"),
  ratio = price.x / price.y)

# 2 another way
ddply(claritycut, .(clarity), 
      function(x) data.frame(cut=x$cut, 
                             rate=x$price / subset(x, cut == "Ideal")$price))

# 3 another way
ddply(claritycut, .(clarity), 
      summarize, cut=cut, rate=price / price[cut == "Ideal"])

最后4)这里是一个单行版本:

ddply(diamonds, .(clarity), 
      function(x) transform(ddply(x, .(cut), 
                                  summarize, rate=mean(price)), 
                            rate=rate/mean(subset(x, cut=="Ideal")$price)))

但太复杂了。

答案 1 :(得分:2)

你不需要知道在施法后有多少级别能够相应地划分,2:ncol(x)将会处理这个问题。这里的一线解决方案虽然简洁,但并不十分清楚。尽量不要强迫你的代码优雅,但可以理解。我发现,当某些东西太漂亮时,以后再复制起来就更难了。

x <- cast(diamonds, clarity ~ cut + ., mean, value="price")
x <- cbind(x[1],x[2:ncol(x)]/x$Ideal)
x <- melt(x) 

或:

x <- cast(diamonds, clarity ~ cut + ., mean, value="price")
x <- melt(cbind(x[1],x[2:ncol(x)]/x$Ideal)) # The last two as one step

答案 2 :(得分:0)

这对表达式args到dlply做了一些有趣的事。

summarize(do.call(merge,c(by="clarity",
                          dlply(
                                ddply(diamonds,.(clarity,cut),
                                      summarize,meanp=mean(price)),
                                .(ifelse(cut!="Ideal","x","y"))))),
          clarity,cut=cut.x,ratio=meanp.x/meanp.y)

这很复杂,但我可以将固定部分包装成一个函数。