Ответ 1
Вот один из способов сделать это:
> 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"
Есть ли способ перемещения столбца из одной позиции в data.frame в следующий - без ввода совершенно нового data.frame()
Например:
a <- b <- c <- d <- e <- f <- g <- 1:100
df <- data.frame(a,b,c,d,e,f,g)
Теперь скажем, что я хотел "g" перед "a"
Я мог бы перепечатать его, так как
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.table
(перемещается по ссылке, без копирования):
setcolorder(dt, moveme(names(dt), "g first"))
Основные параметры:
Смешанные перемещения разделяются точкой с запятой.
Используйте select
из dplyr и его функцию everything()
для перемещения определенных столбцов в начало или конец данных .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" ) и получите dataframe с новыми расположениями столбцов.
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
Я хотел бы предложить другой универсальный рабочий подход, аналогичный предыдущим ответам rcs, Мануэля и Скотта Кайзера, который работает только в определенных случаях:
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")}
}
}}
Использование:
a <- b <- c <- d <- e <- f <- g <- 1:5
df <- data.frame(a,b,c,d,e,f,g)
move(1,"g",df)
Вот простая, но гибкая функция, которую я написал для перемещения столбца в любом месте фрейма данных.
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)))]
}
Использование: Укажите фрейм данных (df
), имя столбца, который вы хотите переместить (move_this
), и имя столбца, к которому вы хотите переместить (next_to_this
). По умолчанию функция будет перемещать столбец move_this
после столбца next_to_this
. Вы можете указать before = TRUE
для перемещения move_this
до next_to_this
.
Примеры:
move.col(df, "b", "g")
move.col(df, "c", "e")
move.col(df, "g", "a", before=TRUE)
move.col(df,c("d","f"),"b", before=TRUE)
Большинство решений кажутся слишком многословными или лишены инкапсуляции. Вот еще один способ решить проблему
push_left <- function(df, pushColNames){
df[, c(pushColNames, setdiff(names(df), pushColNames))]
}
push_left(iris, c("Species", "Sepal.Length"))
Я нашел довольно простой способ сделать это, который соответствовал моим потребностям и не занимал много времени.
У вас есть следующие имена столбцов: "a", "b", "c", "d", "e", "f", "g", "h", "i", "j"
Переместите "d" во вторую позицию (после "a"):
attach(df)
df <- cbind(a, d, df[,c(2:3,5:10)])
Переместите "j" на 4-ю позицию (после "c"):
df <- cbind(df[,c(1:3)], j, df[,c(4:9)])
Из data.table
1.11.0 вы можете использовать setcolorder
(" setcolorder()
теперь принимает меньше ncol(DT)
столбцов для перемещения вперед"):
setDT(df)
setcolorder(df, "g")
df
df
# 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
# ...snip...
Вот одна функция, которая может помочь
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)
}
@Дэвид спросил, как переместить "G" в произвольное положение, например 4. Настроить ответ @rcs,
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])]