代码之家  ›  专栏  ›  技术社区  ›  moodymudskipper

方便地移动柱子

  •  10
  • moodymudskipper  · 技术社区  · 7 年前

    关于如何将专栏移到第一或最后一个位置,有很多很好的问题和答案。

    使用 dplyr 最佳答案分别类似于:

    iris2 <- iris %>% head(2)
    iris2 %>% select( Sepal.Width, everything()) # move Sepal.Width to first
    #   Sepal.Width Sepal.Length Petal.Length Petal.Width Species
    # 1         3.5          5.1          1.4         0.2  setosa
    # 2         3.0          4.9          1.4         0.2  setosa
    
    iris2 %>% select(-Sepal.Width, Sepal.Width) # move Sepal.Width to last
    #   Sepal.Length Petal.Length Petal.Width Species Sepal.Width
    # 1          5.1          1.4         0.2  setosa         3.5
    # 2          4.9          1.4         0.2  setosa         3.0
    

    预期产量:

    iris2 %>% move_at(Species, Sepal.Width, side = "before") 
    #   Sepal.Length Species Sepal.Width Petal.Length Petal.Width
    # 1          5.1  setosa         3.5          1.4         0.2
    # 2          4.9  setosa         3.0          1.4         0.2
    
    iris2 %>% move_at(Species, Sepal.Width, side = "after")
    #   Sepal.Length Sepal.Width Species Petal.Length Petal.Width
    # 1          5.1         3.5  setosa          1.4         0.2
    # 2          4.9         3.0  setosa          1.4         0.2
    
    4 回复  |  直到 6 年前
        1
  •  6
  •   4126cfbe1fd5    7 年前

    不管最初的列顺序如何,这似乎都是可行的(感谢@Moody\u Mudskipper的评论):

    iris %>% select(1:Sepal.Width, -Species, Species, everything()) %>% head(2)
    #>   Sepal.Length Sepal.Width Species Petal.Length Petal.Width
    #> 1          5.1         3.5  setosa          1.4         0.2
    #> 2          4.9         3.0  setosa          1.4         0.2
    iris %>% select(1:Sepal.Width, -Sepal.Width, -Species, Species, everything()) %>% head(2)
    #>   Sepal.Length Species Sepal.Width Petal.Length Petal.Width
    #> 1          5.1  setosa         3.5          1.4         0.2
    #> 2          4.9  setosa         3.0          1.4         0.2
    
        2
  •  14
  •   moodymudskipper    6 年前

    更新:使用 rlang::enquo 我可以把它做得更好,然后用@Zsombor的答案我可以把它做得更短更优雅。答案末尾的旧解(以R为底)

    #' Move column or selection of columns
    #'
    #' Column(s) described by \code{cols} are moved before (default) or after the reference 
    #'   column described by \code{ref}
    #'
    #' @param data A \code{data.frame}
    #' @param cols unquoted column name or numeric or selection of columns using a select helper
    #' @param ref unquoted column name
    #' @param side \code{"before"} or \code{"after"}
    #'
    #' @return A data.frame with reordered columns
    #' @export
    #'
    #' @examples
    #' iris2 <- head(iris,2)
    #' move(iris2, Species, Sepal.Width)
    #' move(iris2, Species, Sepal.Width, "after")
    #' move(iris2, 5, 2)
    #' move(iris2, 4:5, 2)
    #' move(iris2, one_of("Sepal.Width","Species"), Sepal.Width)
    #' move(iris2, starts_with("Petal"), Sepal.Width)
    move <- function(data, cols, ref, side = c("before","after")){
      if(! requireNamespace("dplyr")) 
        stop("Make sure package 'dplyr' is installed to use function 'move'")
      side <- match.arg(side)
      cols <- rlang::enquo(cols)
      ref  <- rlang::enquo(ref)
      if(side == "before") 
        dplyr::select(data,1:!!ref,-!!ref,-!!cols,!!cols,dplyr::everything()) 
      else
        dplyr::select(data,1:!!ref,-!!cols,!!cols,dplyr::everything())
    }
    

    示例:

    iris2 %>% move(Species, Sepal.Width)
    #   Sepal.Length Species Sepal.Width Petal.Length Petal.Width
    # 1          5.1  setosa         3.5          1.4         0.2
    # 2          4.9  setosa         3.0          1.4         0.2
    
    iris2 %>% move(Species, Sepal.Width, "after")
    #   Sepal.Length Sepal.Width Species Petal.Length Petal.Width
    # 1          5.1         3.5  setosa          1.4         0.2
    # 2          4.9         3.0  setosa          1.4         0.2
    
    iris2 %>% move(5, 2)
    #   Sepal.Length Species Sepal.Width Petal.Length Petal.Width
    # 1          5.1  setosa         3.5          1.4         0.2
    # 2          4.9  setosa         3.0          1.4         0.2
    
    iris2 %>% move(4:5, 2)
    #   Sepal.Length Petal.Width Species Sepal.Width Petal.Length
    # 1          5.1         0.2  setosa         3.5          1.4
    # 2          4.9         0.2  setosa         3.0          1.4
    
    iris2 %>% move(one_of("Sepal.Width","Species"), Sepal.Width)
    #   Sepal.Length Sepal.Width Species Petal.Length Petal.Width
    # 1          5.1         3.5  setosa          1.4         0.2
    # 2          4.9         3.0  setosa          1.4         0.2
    
    iris2 %>% move(starts_with("Petal"), Sepal.Width)
    #   Sepal.Length Petal.Length Petal.Width Sepal.Width Species
    # 1          5.1          1.4         0.2         3.5  setosa
    # 2          4.9          1.4         0.2         3.0  setosa
    

    下面是一个仅使用base R编程的简单解决方案:

    move_at <- function(data, col, ref, side = c("before","after")){
      side = match.arg(side)
      col_pos <- match(as.character(substitute(col)),names(data))
      ref_pos <- match(as.character(substitute(ref)),names(data))
      sorted_pos <- c(col_pos,ref_pos)
      if(side =="after") sorted_pos <- rev(sorted_pos)
      data[c(setdiff(seq_len(ref_pos-1),col_pos),
             sorted_pos,
             setdiff(seq_along(data),c(seq_len(ref_pos),col_pos)))]
    }
    
    iris2 %>% move_at(Species, Sepal.Width)
    #   Sepal.Length Species Sepal.Width Petal.Length Petal.Width
    # 1          5.1  setosa         3.5          1.4         0.2
    # 2          4.9  setosa         3.0          1.4         0.2
    
    iris2 %>% move_at(Species, Sepal.Width, "after")
    #   Sepal.Length Sepal.Width Species Petal.Length Petal.Width
    # 1          5.1         3.5  setosa          1.4         0.2
    # 2          4.9         3.0  setosa          1.4         0.2
    
        3
  •  3
  •   Daniel    7 年前

    作为记录,另一个解决方案是

    library(tidyverse)
    data(iris)
    
    iris %>% 
      select(-Species) %>% 
      add_column(Specis = iris$Species, .before = "Petal.Length") %>% 
      head()
    
    #>   Sepal.Length Sepal.Width Specis Petal.Length Petal.Width
    #> 1          5.1         3.5 setosa          1.4         0.2
    #> 2          4.9         3.0 setosa          1.4         0.2
    #> 3          4.7         3.2 setosa          1.3         0.2
    #> 4          4.6         3.1 setosa          1.5         0.2
    #> 5          5.0         3.6 setosa          1.4         0.2
    #> 6          5.4         3.9 setosa          1.7         0.4
    

    创建日期:2018-08-31 reprex package (第0.2.0版)。

        4
  •  2
  •   mt1022    7 年前

    我发现了一个有趣的函数( moveMe ,作者@A5C1D2H2I1M1N2O1R2T1)非常适合这个问题:

    source('https://raw.githubusercontent.com/mrdwab/SOfun/master/R/moveMe.R')
    
    head(iris[ moveMe(names(iris), 'Species before Sepal.Width') ], 2)
    #   Sepal.Length Species Sepal.Width Petal.Length Petal.Width
    # 1          5.1  setosa         3.5          1.4         0.2
    # 2          4.9  setosa         3.0          1.4         0.2
    
    
    head(iris[ moveMe(names(iris), 'Species after Sepal.Width') ], 2)
    #   Sepal.Length Sepal.Width Species Petal.Length Petal.Width
    # 1          5.1         3.5  setosa          1.4         0.2
    # 2          4.9         3.0  setosa          1.4         0.2
    

    它还允许更复杂的指令:

    head(iris[ moveMe(names(iris), 'Species after Sepal.Width; Petal.Width first; Sepal.Length last') ], 2)
    #   Petal.Width Sepal.Width Species Petal.Length Sepal.Length
    # 1         0.2         3.5  setosa          1.4          5.1
    # 2         0.2         3.0  setosa          1.4          4.9
    
    推荐文章