【问题标题】:Using lapply and which to subset dataframe by both characteristic and fuction使用 lapply 和 which 通过特征和功能对数据帧进行子集化
【发布时间】:2018-03-31 20:15:30
【问题描述】:

我有一个包含 5 维数据的数据框,如下所示:

> dim(alldata)
[1] 162   6
> head(alldata)
         value layer Kmultiplier Resolution      Season           Variable
1:  0.01308008     b        .01K        1km    Baseflow Evapotranspiration
2:  0.03974779     b        .01K        1km   Peak Flow Evapotranspiration
3:  0.02396524     b        .01K        1km Summer Flow Evapotranspiration
4: -0.15670996     b        .01K        1km    Baseflow          Discharge
5:  0.06774948     b        .01K        1km   Peak Flow          Discharge
6: -0.04138313     b        .01K        1km Summer Flow          Discharge

我想做的是根据其他列获取数据的某些“特征”的值列的平均值。所以我用 which 将数据子集化为我感兴趣的变量,例如:

> subset=alldata[which(alldata$Variable=="Discharge" & alldata$Resolution=="1km" & alldata$Season=="Peak Flow"),]
> subset
          value layer Kmultiplier Resolution    Season  Variable
1:  0.067749478     b        .01K        1km Peak Flow Discharge
2:  0.058260448     b         .1K        1km Peak Flow Discharge
3: -0.223953725     b         10K        1km Peak Flow Discharge
4:  0.272916114     g        .01K        1km Peak Flow Discharge
5:  0.240135025     g         .1K        1km Peak Flow Discharge
6: -0.216730348     g         10K        1km Peak Flow Discharge
7:  0.088966500     s        .01K        1km Peak Flow Discharge
8: -0.018943754     s         .1K        1km Peak Flow Discharge
9: -0.008339365     s         10K        1km Peak Flow Discharge

这就是我卡住的地方。假设我想要一个向量或“层”列中每个值的平均值列表......所以我最终会得到 3 个数字,一个用于“b”,一个用于“g”,一个用于“s”。我需要制作一堆这样的子集,我认为应用函数可以提供帮助,但是在多个教程和堆栈问题之后,我无法让它工作。一个更简单的例子也可以,像这样:

> A=data.frame(seq(1,9),rep(c("a","b","c"),3),c(rep("type1",3),rep("type2",3),rep("type3",3)),c(rep("place1",2),rep("place2",2),rep("place3",2),rep("place1",2),rep("place2",1)))
> names(A)=c("value","Letter","Type","Place")
> A
  value Letter  Type  Place
1     1      a type1 place1
2     2      b type1 place1
3     3      c type1 place2
4     4      a type2 place2
5     5      b type2 place3
6     6      c type2 place3
7     7      a type3 place1
8     8      b type3 place1
9     9      c type3 place2

从这个简单的例子中,我需要用 Letter 列出的列“value”的平均值来表示“place1”,它应该返回类似:“a=mean value, b=mean value, c=mean value”任何格式都可以。

这是应用功能的工作吗?如果是这样,怎么做?如果没有,请告诉我一个更好的方法来对我的数据进行子集化。

谢谢!

【问题讨论】:

  • 对于因子列的组均值或水平明智,请使用tapply() 函数。
  • 是的,这是*apply 函数的工作。就像@SowmyaS.Manian 所说,如果每个组只需要一个值,第一个选择是tapply,如果你需要与数据框中的行一样多的输出值(每个组中的值相等),则首选ave .

标签: r dataframe subset apply


【解决方案1】:

在您提供的示例数据集上实施的替代解决方案,此处未使用任何apply 系列函数。

使用 dplyr

library(dplyr)
A %>% 
 group_by_(.dots = c("Place","Letter")) %>% 
 summarise(MEAN = mean(value))

# Source: local data frame [6 x 3]
# Groups: Place [?]

#    Place Letter  MEAN
#    <fctr> <fctr> <dbl>
# 1 place1      a     4
# 2 place1      b     5
# 3 place2      a     4
# 4 place2      c     6
# 5 place3      b     5
# 6 place3      c     6

使用by()函数

> by(A$value, A[,c(2,4)], FUN = mean)
# Letter: a
# Place: place1
# [1] 4
# ------------------------------------------------------------ 
# Letter: b
# Place: place1
# [1] 5
# ------------------------------------------------------------ 
# Letter: c
# Place: place1
# [1] NA
# ------------------------------------------------------------ 
# Letter: a
# Place: place2
# [1] 4
# ------------------------------------------------------------ 
# Letter: b
# Place: place2
# [1] NA
# ------------------------------------------------------------ 
# Letter: c
# Place: place2
# [1] 6
# ------------------------------------------------------------ 
# Letter: a
# Place: place3
# [1] NA
# ------------------------------------------------------------ 
# Letter: b
# Place: place3
# [1] 5
# ------------------------------------------------------------ 
# Letter: c
# Place: place3
# [1] 6

【讨论】:

  • 终于有人建议使用未充分利用的by,但你在向量而不是数据帧上运行它。
【解决方案2】:

考虑bytapply面向对象的包装器,它可以跨一个或多个因素(例如地点时间。从数据框列表中,您可以将行绑定到最后一个 df。

df_List <- by(A, A[,c("Place", "Letter")], 
                   FUN = function(i) transform(i, mean = mean(i$value)))

finaldf <- do.call(rbind, dfList)
finaldf
#   value Letter  Type  Place mean
# 1     1      a type1 place1    4
# 7     7      a type3 place1    4
# 4     4      a type2 place2    4
# 2     2      b type1 place1    5
# 8     8      b type3 place1    5
# 5     5      b type2 place3    5
# 3     3      c type1 place2    6
# 9     9      c type3 place2    6
# 6     6      c type2 place3    6

【讨论】:

    【解决方案3】:

    感谢您的建议。遵循this post 的一般建议,我最终选择了 ddply,以便将我的数据转换为更可用的格式。

    这是一个简单的例子:

    > A=data.frame(seq(1,9),rep(c("a","b","c"),3),c(rep("type1",3),rep("type2",3),rep("type3",3)),c(rep("place1",2),rep("place2",2),rep("place3",2),rep("place1",2),rep("place2",1)))
    > names(A)=c("value","Letter","Type","Place")
    > A
      value Letter  Type  Place
    1     1      a type1 place1
    2     2      b type1 place1
    3     3      c type1 place2
    4     4      a type2 place2
    5     5      b type2 place3
    6     6      c type2 place3
    7     7      a type3 place1
    8     8      b type3 place1
    9     9      c type3 place2
    

    然后这是我的代码,用于为每个 place1 和 type1 的值查找“值”的平均值:

    > sub=ddply(A[which(A$Place=="place1" & A$Type=="type1"),],"value",summarize,mean=mean(value,na.rm=T))
    > sub
      value mean
    1     1    1
    2     2    2
    

    由于“sub”已经是一个数据框,因此很容易添加具有其他特征的列,然后绘制这些结果。

    ----------------------------------------------- ----------------------------------

    如果您有兴趣,这里是我实际尝试子集的更复杂的数据集:

    > head(alldata)
            value layer Kmultiplier Resolution      Season           Variable
    1: 0.00000000     b           1        1km    Baseflow Evapotranspiration
    2: 0.01308008     b         .01        1km    Baseflow Evapotranspiration
    3: 0.00000000     b           1        1km   Peak Flow Evapotranspiration
    4: 0.03974779     b         .01        1km   Peak Flow Evapotranspiration
    5: 0.00000000     b           1        1km Summer Flow Evapotranspiration
    6: 0.02396524     b         .01        1km Summer Flow Evapotranspiration
    

    以及我编写的将其子集为可绘制片段的代码行:

      for(j in Season){
        for(i in res){
          ET=ddply(alldata[which(alldata$Variable=="Evapotranspiration" & alldata$Resolution==sprintf("%s",i) & alldata$Season==sprintf("%s",j)),],"Kmultiplier", summarize, mean = mean(value,na.rm=T))
          ET$Variable="Evapotranspiration";ET$Resolution=sprintf("%s",i);ET$Season=sprintf("%s",j)
          S=ddply(alldata[which(alldata$Variable=="Change in Storage" & alldata$Resolution==sprintf("%s",i) & alldata$Season==sprintf("%s",j)),],"Kmultiplier", summarize, mean = mean(value,na.rm=T))
          S$Variable="Change in Storage";S$Resolution=sprintf("%s",i);S$Season=sprintf("%s",j)
          Q=ddply(alldata[which(alldata$Variable=="Discharge" & alldata$Resolution==sprintf("%s",i) & alldata$Season==sprintf("%s",j)),],"Kmultiplier", summarize, mean = mean(value,na.rm=T))
          Q$Variable="Discharge";Q$Resolution=sprintf("%s",i);Q$Season=sprintf("%s",j)
          if(i=="1km"){resbind=rbind(Q,S,ET)}else{resbind2=rbind(resbind,Q,S,ET)}
        } 
        if(j=="Baseflow"){sbind=rbind(resbind2,Q,S,ET)}else if(j=="Peak Flow"){sbind2=rbind(resbind2,sbind,Q,S,ET)}else{ETSQ=rbind(resbind2,sbind2,Q,S,ET)}
      }
      ETSQ$Variable=factor(ETSQ$Variable,levels=c("Change in Storage","Evapotranspiration","Discharge"))
      print(ggplot(data=ETSQ,aes(x=Kmultiplier,y=mean, color=Variable,group=Variable))
            +geom_point()
            +geom_line()
            +labs(x="K scaled by",y="Percent change from Baseline case")
            +scale_y_continuous(labels=percent)
            +facet_grid(Season~Resolution)
            +theme_bw()
      )
      ggsave(sprintf("%s/Plots/SimpleLines/Variable_by_K.png",path),device = NULL,scale=1)
    

    最后得到的情节:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-11
      • 1970-01-01
      • 2021-06-25
      • 2013-07-21
      • 2014-02-10
      • 2016-02-15
      相关资源
      最近更新 更多