2015-06-18 67 views
1

的差异和百分比值,我有这样的R:创建2列与另一列

ID <- c(101,101,101,102,102,102,103,103,103) 
Pt_A <- c(50,100,150,20,30,40,60,80,90) 
df <- data.frame(ID,Pt_A) 

+-----+------+ 
| ID | Pt_A | 
+-----+------+ 
| 101 | 50 | 
| 101 | 100 | 
| 101 | 150 | 
| 102 | 20 | 
| 102 | 30 | 
| 102 | 40 | 
| 103 | 60 | 
| 103 | 80 | 
| 103 | 90 | 
+-----+------+ 

我想创建2个新列与列Pt_A计算值的数据帧。

df$Del_Pt_A <- NthRow(Pt_A) - 1stRow(Pt_A) grouped by ID, where n = 1,2,...n 
df$Perc_Pt_A <- NthRow(Del_Pt_A)/1stRow(Pt_A) grouped by ID, where n = 1,2,...n 

这是我想要的输出

+-----+------+---------+-----------+ 
| ID | Pt_A | Del_Pt_A | Perc_Pt_A| 
+-----+------+---------+-----------+ 
| 101 | 50 | 0  | 0   | 
| 101 | 100 | 50  | 1.0  | 
| 101 | 150 | 100  | 2.0  | 
| 102 | 20 | 0  | 0   | 
| 102 | 30 | 10  | 0.5  | 
| 102 | 40 | 20  | 1.0  | 
| 103 | 60 | 0  | 0   | 
| 103 | 80 | 20  | 0.3  | 
| 103 | 90 | 30  | 0.5  | 
+-----+------+---------+-----------+ 

我目前得到的MS Excel所期望的结果,但我想学做在R来使我的工作效率。我遇到过像dplyr,plyr,data.table等软件包,但我无法用它们解决它。有人可以帮我弄清楚如何解决这个问题。

+1

据透露,' NthRow(Del_Pt_A)/ 1stRow(Pt_A)'简化为'NthRow(Pt_A)/ 1stRow(Pt_A) - 1'。这就是为什么你在下面的答案中看到它。 – Frank

+1

谢谢@Frank,我现在注意到了。 – Sharath

回答

4

这里有一个data.table方式:

library(data.table) 
setDT(df)[,`:=`(
    del  = Pt_A - Pt_A[1], 
    perc  = Pt_A/Pt_A[1]-1 
),by=ID] 

这给

ID Pt_A del  perc 
1: 101 50 0 0.0000000 
2: 101 100 50 1.0000000 
3: 101 150 100 2.0000000 
4: 102 20 0 0.0000000 
5: 102 30 10 0.5000000 
6: 102 40 20 1.0000000 
7: 103 60 0 0.0000000 
8: 103 80 20 0.3333333 
9: 103 90 30 0.5000000 
+3

优秀的解决方案!我将使用这个。 Data.table非常方便,易于理解。 – Sharath

2

在这里,在基础R另一种选择:

cbind(df, 
     do.call(rbind,by(df,df$ID, 
    function(x) 
      setNames(data.frame(x$Pt_A-x$Pt_A[1], 
         x$Pt_A/x$Pt_A[1]-1), 
        c('Del_Pt_A','Perc_Pt_A'))))) 

#  ID Pt_A Del_Pt_A Perc_Pt_A 
# 101.1 101 50  0 0.0000000 
# 101.2 101 100  50 1.0000000 
# 101.3 101 150  100 2.0000000 
# 102.1 102 20  0 0.0000000 
# 102.2 102 30  10 0.5000000 
# 102.3 102 40  20 1.0000000 
# 103.1 103 60  0 0.0000000 
# 103.2 103 80  20 0.3333333 
# 103.3 103 90  30 0.5000000 

我使用:

  • by按组应用的功能,其结果是一个列表
  • do.call(rbind, list_by)到列表变换为data.frame
  • cbind到结果添加到初始data.frame
+0

你可以使用(x,...)''摆脱'x $'和'data.frame(del = ...,perc = ...)'来摆脱'setNames' ...? – Frank

+1

@Frank当然..这是data.table解决方案,我在最后一分钟转换为基础解决方案....虽然,我会注意使用'with'(个人喜好),但肯定会将'$'转换为'['。 – agstudy