【问题标题】:R equivalent of .first or .last sas operatorR 等效于 .first 或 .last sas 运算符
【发布时间】:2012-12-07 15:03:38
【问题描述】:

有谁首先知道 SAS 的最佳 R 替代品是什么。或最后。运营商?我没有找到。

SAS 拥有第一。最后。自动变量,用于识别具有特定变量的相同值的组中的第一条和最后一条记录;因此在以下数据集中定义了 FIRST.model 和 LAST.model:

Model,SaleID,First.Model,Last.Model
Explorer,1,1,0
Explorer,2,0,0
Explorer,3,0,0
Explorer,4,0,1
Civic,5,1,0
Civic,6,0,0
Civic,7,0,1

【问题讨论】:

  • 我无法访问 SAS - .first 或 .last 在做什么?可以举个例子吗?
  • FIRST.LAST. 不是运算符;它们是自动 SAS 数据步进变量,定义为在 BY 语句处理期间指示列值变化。
  • 我不认为。但这个链接似乎有答案。 stat.ethz.ch/pipermail/r-help/2010-November/260997.html
  • 由于我们中没有多少人知道 SAS,如果你能解释你想做什么,它可能会更快得到答案。
  • diff() 也可能有一个简单的解决方案...

标签: r sas


【解决方案1】:

听起来您正在寻找!duplicatedfromLast 参数为FALSETRUE

d <- datasets::Puromycin

d$state
# [1] treated   treated   treated   treated   treated   treated   treated  
# [8] treated   treated   treated   treated   treated   untreated untreated
#[15] untreated untreated untreated untreated untreated untreated untreated
#[22] untreated untreated
#Levels: treated untreated
!duplicated(d$state)
# [1]  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
#[13]  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
!duplicated(d$state,fromLast=TRUE)
# [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE
#[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE

此函数有一些注意事项和极端情况行为,您可以通过帮助文件 (?duplicated) 找到。

【讨论】:

    【解决方案2】:

    更新(先读)

    如果您真的只对行索引感兴趣,那么直接使用splitrange 可能会有用。以下假设您的数据集中的行名是按顺序编号的,但也可能进行调整。

    irisFirstLast <- sapply(split(iris, iris$Species), 
                            function(x) range(as.numeric(rownames(x))))
    irisFirstLast              ## Just the indices
    #      setosa versicolor virginica
    # [1,]      1         51       101
    # [2,]     50        100       150
    iris[irisFirstLast[1, ], ] ## `1` would represent "first"
    #     Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
    # 1            5.1         3.5          1.4         0.2     setosa
    # 51           7.0         3.2          4.7         1.4 versicolor
    # 101          6.3         3.3          6.0         2.5  virginica
    iris[irisFirstLast, ]      ## nothing would represent both first and last
    #     Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
    # 1            5.1         3.5          1.4         0.2     setosa
    # 50           5.0         3.3          1.4         0.2     setosa
    # 51           7.0         3.2          4.7         1.4 versicolor
    # 100          5.7         2.8          4.1         1.3 versicolor
    # 101          6.3         3.3          6.0         2.5  virginica
    # 150          5.9         3.0          5.1         1.8  virginica
    
    d <- datasets::Puromycin   
    dFirstLast <- sapply(split(d, d$state), 
                         function(x) range(as.numeric(rownames(x))))
    dFirstLast
    #      treated untreated
    # [1,]       1        13
    # [2,]      12        23
    d[dFirstLast[2, ], ]       ## `2` would represent `last`
    #    conc rate     state
    # 12  1.1  200   treated
    # 23  1.1  160 untreated
    

    如果使用命名行,一般方法是相同的,但您必须自己指定范围。这是一般模式:

    datasetFirstLast <- sapply(split(dataset, dataset$groupingvariable), 
                               function(x) c(rownames(x)[1], 
                                             rownames(x)[length(rownames(x))]))
    

    初始答案(已编辑)

    如果您有兴趣提取行而不是将行号用于其他目的,您还可以探索data.table。以下是一些示例:

    library(data.table)
    DT <- data.table(iris, key="Species")
    DT[J(unique(Species)), mult = "first"]
    #       Species Sepal.Length Sepal.Width Petal.Length Petal.Width
    # 1:     setosa          5.1         3.5          1.4         0.2
    # 2: versicolor          7.0         3.2          4.7         1.4
    # 3:  virginica          6.3         3.3          6.0         2.5
    DT[J(unique(Species)), mult = "last"]
    #       Species Sepal.Length Sepal.Width Petal.Length Petal.Width
    # 1:     setosa          5.0         3.3          1.4         0.2
    # 2: versicolor          5.7         2.8          4.1         1.3
    # 3:  virginica          5.9         3.0          5.1         1.8
    DT[, .SD[c(1,.N)], by=Species]
    #       Species Sepal.Length Sepal.Width Petal.Length Petal.Width
    # 1:     setosa          5.1         3.5          1.4         0.2
    # 2:     setosa          5.0         3.3          1.4         0.2
    # 3: versicolor          7.0         3.2          4.7         1.4
    # 4: versicolor          5.7         2.8          4.1         1.3
    # 5:  virginica          6.3         3.3          6.0         2.5
    # 6:  virginica          5.9         3.0          5.1         1.8
    

    最后一种方法非常方便。例如,如果您想要每组的前三行和后三行,您可以使用:DT[, .SD[c(1:3, (.N-2):.N)], by=Species](仅供参考:.N 表示每组的案例数。

    其他有用的方法包括:

    DT[, tail(.SD, 2), by = Species] ## last two rows of each group
    DT[, head(.SD, 4), by = Species] ## first four rows of each group
    

    【讨论】:

    • 我认为这里的答案真的只是使用by。我对在实践中如何使用first.last. 的理解是设置处理按组子集的过程。
    • @mnel,从未使用过 SAS,有点匆忙阅读了这篇文章。 data.table 选项是我首先想到的,因为我最近一直在探索这个包。感谢您向我指出这一点。我更新了一些可能更相关的内容,但仍然不确定first.last. 在实践中的使用方式。
    【解决方案3】:

    带有 n=1 选项的 head 和 tail 函数结合 by 是一个不错的方法。 请参阅 SAS 和 SPss 用户的 R** (Robert Muenchen) 使用感兴趣的变量创建数据框 即最后。

    dfby<- data.frame(df$var1, df$var2)
    mylastList<-by(df,dfby,tail, n=1)
    #turn into a dataframe
    mylastDF<-do.call(rbind,mylastList)
    

    【讨论】:

      【解决方案4】:

      这是一个 dplyr 解决方案:

      # input
      dataset <- structure(list(Model = structure(c(2L, 2L, 2L, 2L, 1L, 1L, 1L
      ), .Label = c("Civic", "Explorer"), class = "factor"), SaleID = 1:7), .Names = c("Model", 
      "SaleID"), class = "data.frame", row.names = c(NA, -7L))
      
      
      # code 
      library(dplyr)
      
      dataset %>% 
      
        group_by(Model) %>%
      
        mutate(
                "First"        = row_number() == min( row_number() ),
                "Last"         = row_number() == max( row_number() )
        )
      
      # output:
      
           Model SaleID First  Last
          <fctr>  <int> <lgl> <lgl>
      1 Explorer      1  TRUE FALSE
      2 Explorer      2 FALSE FALSE
      3 Explorer      3 FALSE FALSE
      4 Explorer      4 FALSE  TRUE
      5    Civic      5  TRUE FALSE
      6    Civic      6 FALSE FALSE
      7    Civic      7 FALSE  TRUE
      

      PS:如果您没有安装 dplyr,请运行:

      install.packages("dplyr")
      

      【讨论】:

        【解决方案5】:

        下面的函数是基于@Joe 对First/Last 的描述。
        该函数返回一个向量列表。

        每个列表条目对应于数据框的列(即数据集的特征或变量)
        然后,在给定的列表条目中,存在相关的索引 到每个观察类别的第一个(或最后一个)元素。

        示例用法:

        # Pass in your data frame, and indicate whether or not you want to find Last or find First. 
        # Assign to the appropriate variable
        first <- findFirstLast(myDF)
        last  <- findFirstLast(myDF, findFirst=FALSE)
        

        使用data(iris) 的示例

        data(iris)
        first <- findFirstLast(iris)
        last  <- findFirstLast(iris, findFirst=FALSE)
        

        每个物种的观察:

         first$Species
         #    setosa versicolor  virginica 
         #        1         51        101 
        
         last$Species
         #    setosa versicolor  virginica 
         #        50        100        150 
        

        每次第一次观察一个 sepcies 时获取整行

        iris[first$Species, ]
        #      Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
        #  1            5.1         3.5          1.4         0.2     setosa
        #  51           7.0         3.2          4.7         1.4 versicolor
        #  101          6.3         3.3          6.0         2.5  virginica
        




        函数代码 findFirstLast():

          findFirstLast <- function(myDF, findFirst=TRUE) {
          # myDF should be a data frame or matrix 
        
            # By default, this function finds the first occurence of each unique value in a column
            # If instead we want to find last, set findFirst to FALSE.  This will give `maxOrMin` a value of -1
            #    finding the min of the negative indecies is the same as finding the max of the positive indecies. 
            maxOrMin <- ifelse(findFirst, 1, -1) 
        
        
            # For each column in myDF, make a list of all unique values (`levs`) and iterate over that list, 
            #   finding the min (or max) of all the indicies of where that given value appears within the column  
            apply(myDF, 2, function(colm) {
                levs <- unique(colm)
                sapply(levs, function(lev) {
                  inds <- which(colm==lev)
                  ifelse(length(inds)==0, NA, maxOrMin*min(inds*maxOrMin) ) 
                })   
              })
          }
        

        【讨论】:

        • 也许将函数定义放在任何使用它的代码之前?
        • @Dason,也许吧。但在这种情况下,函数的内部结构不如用法重要。
        猜你喜欢
        • 1970-01-01
        • 2020-10-11
        • 1970-01-01
        • 2014-10-02
        • 2014-10-16
        • 2019-07-06
        • 2012-02-08
        • 2018-12-29
        • 1970-01-01
        相关资源
        最近更新 更多