【问题标题】:Selection of levels of factors within a factor因子内因子水平的选择
【发布时间】:2015-08-04 20:23:46
【问题描述】:

这是我的例子:

df<-data.frame(ID=as.factor(c(rep("A",20),rep("B",15))),var=as.factor(c(rep("w",5),rep("x",10),rep("y",12),rep("z",8))), obs=runif(35,0,10))

我想要做的是,对于每个“ID”,能够随机选择一个“var”,并且可能通过选择“obs”最多的“var”。因此,例如,它可以随机给出:

   ID  var       obs
6   A   x 3.44405412
7   A   x 1.50957637
8   A   x 8.22009420
9   A   x 7.47094473
10  A   x 8.26098410
11  A   x 9.62919537
12  A   x 0.10393890
13  A   x 0.11298502
14  A   x 4.33822574
15  A   x 4.20109035
28  B   z 1.07697286
29  B   z 8.40864310
30  B   z 7.62563257
31  B   z 0.06885177
32  B   z 4.33959316
33  B   z 7.98303782
34  B   z 8.38335593
35  B   z 4.52110318

提前感谢您的帮助。

【问题讨论】:

    标签: r dataframe factors


    【解决方案1】:

    这是另一种 data.table 方法。开始...

    library(data.table)
    setDT(df)
    

    然后,为每个ID 选择var

    # var with highest #obs
    idvar_selected = df[,.(var = .SD[,.N,by=var][which.max(N)]$var), by=ID]
    
    # or... at random, weighted by #obs
    idvar_selected = df[,.(var = sample(var,1)), by=ID]
    

    然后使用选择“加入”:

    df[idvar_selected, on=c("ID","var")]
    

    【讨论】:

    • 由于某种原因,akrun 的代码让 RStudio 每次尝试在包含我的数据的完整 df 上运行它时都会遇到致命错误。你的没有这个问题,并且在完整的 df 上工作得很好,所以谢谢!
    • @user2092517 嗯,不知道为什么会这样,因为我对 Rstudio 没有太多经验。如果您一直遇到此类问题,您可能会考虑制作一个可重现的示例并使用 Rstudio 支持频道询问它。您也可以通过评论 akrun 的答案来询问 akrun 是否有任何想法。
    【解决方案2】:

    一个选项使用data.table

    我们将“data.frame”转换为“data.table”(setDT(df))。按“ID”和“var”分组,我们创建了一个变量“N”,它给出了每个组的行数 (.N)。然后,我们按“ID”分组并将max 值为“N”(.SD[N==max(N)])的行子集。 'N' 列可以分配给 'NULL',因为它在预期输出中不需要。

    library(data.table)
    setDT(df)[,N := .N  , by = .(ID, var)][, .SD[N==max(N)] ,
            by = .(ID)][, N:= NULL][]
    #    ID var       obs
    # 1:  A   x 9.2044378
    # 2:  A   x 2.7973557
    # 3:  A   x 7.6382046
    # 4:  A   x 8.0163062
    # 5:  A   x 2.5472509
    # 6:  A   x 6.0488886
    # 7:  A   x 3.7073495
    # 8:  A   x 6.7169025
    # 9:  A   x 6.7298231
    #10:  A   x 3.2043056
    #11:  B   z 5.9973018
    #12:  B   z 6.3014766
    #13:  B   z 0.4663503
    #14:  B   z 3.1951313
    #15:  B   z 2.3874890
    #16:  B   z 3.6881753
    #17:  B   z 1.4802475
    #18:  B   z 9.3776173
    

    通过分配新列,我们正在更改原始数据集“df”。我们可以稍后通过

    从原始数据集中删除该列
    df[, N:=NULL]
    

    或修改上述代码而不分配 (:=) 以便原始数据集保持不变。我们将.SDSubset of Datatable.N 连接起来以创建新列'N',然后像以前一样对行进行子集化。

    setDT(df)[, c(list(N=.N), .SD) ,by =.(ID, var)][, 
                         .SD[N==max(N)], by =ID][, N:= NULL][]
    

    或者按照@Frank 的建议,我们可以copy(.SD) 避免更改原始数据集,然后分配'N',并像以前一样。

    setDT(df)[,copy(.SD)][,N := .N , by = .(ID, var)][,
                              .SD[N==max(N)] ,  by = .(ID)][]
    

    如果我们想在每个 'ID' 中随机选择 'var',我们可以使用 sample 选择按 'ID' 分组的单个 'var',得到一个逻辑向量 (var==sample(var, 1)]) 并对行进行子集化

    setDT(df)[, .SD[var==sample(var, 1)] , by =ID]
    

    数据

    set.seed(24)
    df <- data.frame(ID=as.factor(c(rep("A",20),rep("B",15))),
             var=as.factor(c(rep("w",5),rep("x",10),rep("y",12),rep("z",8))), 
             obs=runif(35,0,10))
    

    【讨论】:

    • 但是这段代码所做的只是在原始df中添加N列;没有一种解决方案可以让我一次性获得预期的输出吗?如果我使用此代码,似乎我必须根据 N 对原始 df 进行子集化。之前的评论是我,我看到你编辑了你的答案,并认为你修正了我刚刚提出的观点。
    • 似乎运行良好!非常感谢!
    • 像 OP 一样,我在运行代码时看到 N 列添加到 df。不确定您是否知道在链中删除它的方法,但您可以在单独的行中这样做。
    • 好的,np。顺便说一句,花式连接也是一种选择,例如 df[ df[,.(var=sample(var,1)),by=ID], on=c("ID","var")] 我猜这使用二进制搜索而不是 var==sample(var,1) 中的矢量扫描,这可能会更快。
    • 当然没问题 :) 您的新解决方案可以改为使用 copy(.SD) 作为第一步,例如 setDT(df)[,copy(.SD)][,N := .N , by = .(ID, var)][, .SD[N==max(N)] , + by = .(ID)][]
    猜你喜欢
    • 2017-04-04
    • 1970-01-01
    • 1970-01-01
    • 2018-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-17
    相关资源
    最近更新 更多