【问题标题】:Conditional linear fitting with dplyr使用 dplyr 进行条件线性拟合
【发布时间】:2016-10-13 13:03:38
【问题描述】:

我正在尝试对分组数据进行线性拟合。

但是,我还想在整个拟合过程中添加一些条件,但是当我对某些条件进行子集化时未能做到这一点。

set.seed(183)
library(dplyr)
V <- rep(seq(1,8),3)
value = c(c(sort(runif(5,0.001,1)),rep(0,3)),c(sort(runif(5,0.001,1)),rep(0,2),runif(1,0.001,1)),c(sort(runif(5,0.001,1)),rep(0,2),runif(1,0.001,1)))
group=rep(letters[1:3],each=8)

df <- data.frame(group,V,value)

#    > df
#   group V      value
#1      a 1 0.15087459
#2      a 2 0.35408406
#3      a 3 0.47339320
#4      a 4 0.67614665
#5      a 5 0.98273932
#6      a 6 0.00000000
#7      a 7 0.00000000
#8      a 8 0.00000000
#9      b 1 0.32821476
#10     b 2 0.35737009
#11     b 3 0.58821689
#12     b 4 0.81088053
#13     b 5 0.99122633
#14     b 6 0.00000000
#15     b 7 0.00000000
#16     b 8 0.03697432
#17     c 1 0.12940226
#18     c 2 0.41918905
#19     c 3 0.66020739
#20     c 4 0.84124155
#21     c 5 0.95052213
#22     c 6 0.00000000
#23     c 7 0.00000000
#24     c 8 0.15071444

我在每个组内的条件是

1) 如果所有最后 3 个 value==0 仅在 V&gt;=4&amp;V&lt;=5 时适合

2)如果最后 2 个 value&gt;0 仅在 V&gt;=7 时适合。

这是我为执行此操作而编写的函数

   get_slope <- function(df){
  if (tail(df$value,3)==0)
    slp = coef(lm(value~V, data=subset(df,V>=4&V<=5)))[2]
    else 
    if (any(tail(df$value,3)>=0))
        slp = coef(lm(value ~ V, data=subset(df,V>=7)))[2]
    return(slp)
  }

df_slope <- df%>%
  group_by(group)%>%
  do(.,slope=get_slope(df))

Warning messages:
1: In if (tail(df$value, 3) == 0) slp = coef(lm(value ~ V, data = subset(df,  :
  the condition has length > 1 and only the first element will be used
2: In if (tail(df$value, 3) == 0) slp = coef(lm(value ~ V, data = subset(df,  :
  the condition has length > 1 and only the first element will be used
3: In if (tail(df$value, 3) == 0) slp = coef(lm(value ~ V, data = subset(df,  :
  the condition has length > 1 and only the first element will be used

最后我想得到每组的斜率值。

有没有简单的方法可以做到这一点?

提前非常感谢!

【问题讨论】:

    标签: r dplyr lm broom


    【解决方案1】:

    条件tail(df$value,3)==0 将给出 3 个 T/F 值。我在下面的函数中交换它,并使用 split 和 plyr::ldply 而不是 dplyr。

    df1<-split(df, df$group)
    get_slope <- function(df){
      if (any(!tail(df$value,3)==0)) coef(lm(value ~ V, data=subset(df,V>=7)))[2]
      else  coef(lm(value~V, data=subset(df,V>=4&V<=5)))[2]
    }
    library(plyr)
    ldply(df1, get_slope)
    
      .id          V
    1   a 0.06940913
    2   b 0.20794964
    3   c 0.84607397
    

    请求的dplyr方法:

    df_slope <- df %>% 
                   group_by(group) %>% 
                   do(.,slope=get_slope(.))
    
    df_slope$slope <- df_slope$slope %>% unlist %>% as.numeric
    df_slope
    
    Source: local data frame [3 x 2]
    Groups: <by row>
    
       group      slope
      (fctr)      (dbl)
    1      a 0.06940913
    2      b 0.20794964
    3      c 0.84607397
    

    【讨论】:

    • 感谢您的回答。为什么我们不能在 dplyr 链中做到这一点?
    • 当然可以。请注意,管道可能不如 ldply 函数高效。
    • 如果是这样,您还会添加 dplyr way 作为您帖子的答案吗?
    • dplyr 选项已添加。个人更喜欢更直接的ldply。
    • do 选项不必那么复杂。使用 do(data.frame(slope = get_slope(.))) 或使用来自 tidyr 的 %&gt;% unnest 结束链以重现 ldply 结果。
    【解决方案2】:

    我想到的是循环所有级别并应用该功能。

    1.设置一个数组接收所有结果

     slp = c() 

    2.循环组中的所有级别,如果条件满足则执行操作。

     for(group in unique(df$group)){
         if(sum(tail(df$value[which(df$group==group)],3) == c(0,0,0))==3){
           slp = c(slp,coef(lm(值~V, 数据=子集(df,V>=4&V=0)){
       slp = c(slp, coef(lm(value ~ V, data=subset(df,V>=7)))[2])
         }} 
    3.打印结果
    slp
             a b c
    0.06448301 0.55057826 0.55057826 

    我的解决方案可能并不像预期的那样简单,但应该很容易理解,希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 2019-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-17
      • 2014-04-15
      • 2021-11-14
      相关资源
      最近更新 更多