programing tip

다시 입력하지 않고 data.frame () 내에서 열 이동

itbloger 2021. 1. 9. 09:34
반응형

다시 입력하지 않고 data.frame () 내에서 열 이동


완전히 새로운 data.frame ()을 입력하지 않고 data.frame의 한 위치에서 다음 위치로 열을 이동하는 방법이 있습니까?

예를 들면 :

a <- b <- c <- d <- e <- f <- g <- 1:100
df <- data.frame(a,b,c,d,e,f,g)

이제 "a"앞에 "g"를 원한다고 가정 해 보겠습니다.

다시 입력 할 수 있습니다.

df <- data.frame(g,a,b,c,d,e,f)

그러나 더 빠른 방법이 없습니까? (1500 개 이상의 열을 상상해보세요)


한 가지 방법은 다음과 같습니다.

> col_idx <- grep("g", names(df))
> df <- df[, c(col_idx, (1:ncol(df))[-col_idx])]
> names(df)
[1] "g" "a" "b" "c" "d" "e" "f"

subset함수에는 select이름으로 열 범위를 선택하는 편리한 방법을 제공 하는 멋진 인수가 있습니다.

df <- subset(df, select=c(g,a:f))

최근에이 함수를 작성했습니다 moveme. 열 순서를 섞을 목적으로 벡터에서 작동하도록 설계되었습니다.

기능은 다음과 같습니다.

moveme <- function (invec, movecommand) {
  movecommand <- lapply(strsplit(strsplit(movecommand, ";")[[1]], 
                                 ",|\\s+"), function(x) x[x != ""])
  movelist <- lapply(movecommand, function(x) {
    Where <- x[which(x %in% c("before", "after", "first", 
                              "last")):length(x)]
    ToMove <- setdiff(x, Where)
    list(ToMove, Where)
  })
  myVec <- invec
  for (i in seq_along(movelist)) {
    temp <- setdiff(myVec, movelist[[i]][[1]])
    A <- movelist[[i]][[2]][1]
    if (A %in% c("before", "after")) {
      ba <- movelist[[i]][[2]][2]
      if (A == "before") {
        after <- match(ba, temp) - 1
      }
      else if (A == "after") {
        after <- match(ba, temp)
      }
    }
    else if (A == "first") {
      after <- 0
    }
    else if (A == "last") {
      after <- length(myVec)
    }
    myVec <- append(temp, values = movelist[[i]][[1]], after = after)
  }
  myVec
}

사용법은 간단합니다. 다음을 시도하십시오.

moveme(names(df), "g first")
moveme(names(df), "g first; a last; e before c")

물론 열을 재정렬하는 데 사용하는 data.frame것은 간단합니다.

df[moveme(names(df), "g first")]

그리고 data.tables (참조로 이동, 사본 없음) :

setcolorder(dt, moveme(names(dt), "g first"))

기본 옵션은 다음과 같습니다.

  • 먼저
  • 마지막
  • 전에

복합 이동은 세미콜론으로 구분됩니다.


사용 select로부터 dplyr의 패키지와 그 everything()기능은 data.frame의 시작이나 끝으로 특정 열을 이동합니다.

처음으로 이동 :

library(dplyr)
df %>%
  select(g, everything())

끝으로 이동 :

df %>%
  select(-a, everything())

또는 %>%파이프 연산자가 없으면 각각 select(df, g, everything())select(df, -a, everything())입니다.


여기 내 해결책이 있습니다.

df[c(7,1:6)]

또는 열 이름으로 재정렬 할 수도 있습니다.

df[c("g",names(df)[-7])]

이것은 약간 더 우아하고 맨 왼쪽의 처음 몇 개의 열을 정렬하고 나머지는 오른쪽에 정렬하지 않은 채로 둘 수 있습니다.

ordered_columns_leftside=c('var10','var34','var8')
df=df[c(ordered_columns_leftside, setdiff(names(df),ordered_columns_leftside))]

다음은 열 이름을 기반으로 거대한 데이터 프레임에서 'n'번째 열을 2 번째 위치로 이동하는 데 사용한 유사한 방법입니다.

열을 첫 번째 위치로 이동 :

## Move a column with name "col_name"  to first column 
colX <- grep("^col_name", colnames(df.original)) 
# get the column position from name 

df.reordered.1 <- df.original[,c(colX,1:(colX-1), (colX+1):length(df.original))]  
# get new reordered data.frame
# if the column is the last one, error "undefined columns selected" will show up. Then do the following command instead of this

df.reordered.1 <- df.original[,c(colX,1:(colX-1)]  
# get new reordered data.frame, if the column is the last one

어디에서나 'n'번째 위치까지

## Move a column with name "col_name"  to column position "n", 
## where n > 1 (in a data.frame "df.original")

colX <- grep("^col_name", colnames(df.original)) 
# get the column position from name 

n <- 2 
# give the new expected column position (change to the position you need) 

df.reordered.2 <- df.original[,c(1:(n-1), colX, n:(colX-1), (colX+1):length(df.original))] 
# get new reordered data.frame

## Optional; to replace the original data frame with sorted data.frame 
## if the sorting looks good
df.original <- df.reordered.2
rm(df.reordered.2) # remove df

이것은 매우 오래된 게시물이지만 데이터 프레임 내에서 열 위치를 동적으로 변경하는이 코드를 개발했습니다. n 값과 열 이름 (여기서 "g")을 변경하고 새 열 배열로 데이터 프레임을 가져옵니다.

df1 = subset(df, select = c(head(names(df),n=3),"g", names(df) [! names(df) %in% c(head(names(df),n=3),"g")]))

예에서와 같이 순서 변경이 시프트 인 shift경우 taRifx패키지 함수를 사용할 수 있습니다 . 벡터에 작용하므로 열 이름에 적용합니다.

> a <- b <- c <- d <- e <- f <- g <- 1:5
> df <- data.frame(a,b,c,d,e,f,g)
> df[, taRifx::shift(seq_along(df),-1)]
  g a b c d e f
1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5

사실이 shift함수는 데이터 프레임에도 적용 할 수 있지만 예상과는 다릅니다. 함수를 작성할 수 있습니다.

> shift_df <- function(df, n) df[, taRifx::shift(seq_along(df),n)]
> shift_df(df, -1)
  g a b c d e f
1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5
> shift_df(df, 2)
  c d e f g a b
1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5

다음은 데이터 프레임에서 열을 이동하기 위해 작성한 간단하지만 유연한 함수입니다.

move.col <- function(df, move_this, next_to_this, before = FALSE) {
  if (before==FALSE)
    df[,c(match(setdiff(names(df)[1:which(names(df)==next_to_this)],move_this),names(df)),
          match(move_this,names(df)),
          match(setdiff(names(df)[which(names(df)==next_to_this):ncol(df)],c(next_to_this,move_this)),names(df)))]
  else
    df[,c(match(setdiff(names(df)[1:(which(names(df)==next_to_this))],c(next_to_this,move_this)),names(df)),
          match(move_this,names(df)),
          match(setdiff(names(df)[(which(names(df)==next_to_this)):ncol(df)],move_this),names(df)))]
}

Usage: Specify the data frame (df), the column name you want to move (move_this), and the column name of which you want to move beside (next_to_this). By default, the function will move the move_this column after the next_to_this column. You can specify before = TRUE to move move_this before next_to_this.

Examples:

  1. Move "b" after "g" (i.e., make "b" last column).

move.col(df, "b", "g")

  1. Move "c" after "e".

move.col(df, "c", "e")

  1. Move "g" before "a" (i.e., make "g" first column).

move.col(df, "g", "a", before=TRUE)

  1. Move "d" and "f" before "b" (i.e., move multiple columns).

move.col(df,c("d","f"),"b", before=TRUE)


Most solutions seem overly verbose or lack encapsulation. Here's another way to solve the problem

push_left <- function(df, pushColNames){
    df[, c(pushColNames, setdiff(names(df), pushColNames))]
}

push_left(iris, c("Species", "Sepal.Length"))

I found a pretty simple way of doing this that suited my needs and doesn't take much time.

You have the following column names: "a", "b", "c", "d", "e", "f", "g", "h", "i", "j"

Move "d" to second position (after "a"):

attach(df)

df <- cbind(a, d, df[,c(2:3,5:10)])

Move "j" to 4th position (after "c"):

df <- cbind(df[,c(1:3)], j, df[,c(4:9)])

I would like to contribute another universal working approach, similar to the previous answers of rcs, Manuel and Scott Kaiser, which only work in specific cases:

move<-function(new.pos,nameofcolumn,dfname) {
  col_idx <- grep(nameofcolumn, names(dfname))
  if (length(col_idx)==0){print("invalid column name");return(dfname)} else {
  if(new.pos>ncol(dfname)){print("invalid column number");return(dfname)} else {
  if (new.pos==1) {
    b<-dfname[ , c( col_idx, c((new.pos):ncol(dfname))[-(abs(new.pos-1-col_idx))] )]  
    }
  else if(col_idx==1 & new.pos==ncol(dfname)){
    b<-dfname[ , c((1:(new.pos-1)+1), col_idx )] 
    }
  else if(col_idx==1){
    b<-dfname[ , c((1:(new.pos-1)+1), col_idx, c((new.pos+1):ncol(dfname)) )] 
    }
  else if(new.pos==ncol(dfname)){
    b<-dfname[ , c((1:(new.pos))[-col_idx], col_idx)] 
    }
  else if(new.pos>col_idx){
    b<-dfname[ , c((1:(new.pos))[-col_idx], col_idx, c((new.pos+1):ncol(dfname)) )] 
    } 
  else{
    b<-dfname[ , c((1:(new.pos-1)), col_idx, c((new.pos):ncol(dfname))[-(abs(new.pos-1-col_idx))] )]
    }
  return(b)
  if(length(ncol(b))!=length(ncol(dfname))){print("error")}
  }
}}

Usage:

a <- b <- c <- d <- e <- f <- g <- 1:5
df <- data.frame(a,b,c,d,e,f,g)
move(1,"g",df)

Here is one function that might help

  • df: the dataframe
  • ColName: the name of the column(s) to be moved
  • Position: the column number that you want the moved column to appear

moveCol <- function(df,ColName,Position=1) {
    D <- dim(df)[2]
    DFnames <- names(df)
    if (Position>D+1 | Position<1) {
        warning(paste0('Column position ',sprintf('%d',Position), ' is out of range [1-',sprintf('%d',D),']'))
        return()
    }
    for (i in ColName) {
        x <- i==DFnames
        if (all(!x)) {
            warning(paste0('Column \"', i, '\" not found'))
        } else {
            D1 <- seq(D)
            D1[x] = Position - 0.5
            df<- df[order(D1)]
        }
    }
    return(df)
}

@David asked how to move "G" to an arbitrary position, such as 4. Building on @rcs answer,

new.pos <- 4
col_idx <- grep("g", names(df))
df      <- df[ , c((1:new.pos)[-col_idx], col_idx, c((new.pos):ncol(df))[-col_idx])]

ReferenceURL : https://stackoverflow.com/questions/3369959/moving-columns-within-a-data-frame-without-retyping

반응형