Перемещение столбцов в 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)
Теперь предположим, что я хотел «g» перед «a»,
- Использование R для отображения всех файлов с указанным расширением
- Напишите много файлов в цикле for
- Как создать пример данных из частных данных (заменяя имена переменных и уровни владельцами неинформативных мест)?
- Что делает функция «pol» на самом деле?
- Как удалить все объекты, кроме одного из рабочей области в R?
Я мог бы перепечатать его, так как
df <- data.frame(g,a,b,c,d,e,f)
Но не быстрее? (Представьте себе 1500+ столбцов)
- Настройка прокси для R
- Слишком мало периодов для разложения ()
- листинг содержимого файла данных R без загрузки
- Не удалось установить пакеты в последней версии RStudio и R версии.3.1.1
- конвертировать письма в номера
- Изменение имени переменной в цикле for с использованием R
- Как суммировать числовые элементы списка
- Автоматически создавать формулы для всех возможных линейных моделей
Вот один из способов сделать это:
> 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
столбцов в вашем data.frame
является простым:
df[moveme(names(df), "g first")]
И для data.table
s (перемещается по ссылке, без копирования):
setcolorder(dt, moveme(names(dt), "g first"))
Основные параметры:
- первый
- последний
- до
- после
Смешанные перемещения разделяются точкой с запятой.
Используйте select
из пакета dplyr и его функции everything()
для перемещения определенных столбцов в начало или конец файла data.frame.
Перейдите к началу:
library(dplyr) df %>% select(g, everything())
Перейти к концу:
df %>% select(-a, everything())
Или без оператора %>%
pipe, они будут 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)] gabcdef 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) gabcdef 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) cdefgab 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, Manuel и Scott Kaiser, которые работают только в конкретных случаях:
move<-function(new.pos,nameofcolumn,dfname) { col_idx <- grep(nameofcolumn, names(dfname)) if (length(col_idx)==0){print("invalid column name")} else { if(new.pos>ncol(dfname)){print("invalid column number")} 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
.
Примеры:
- Переместить «b» после «g» (т. Е. Сделать последний столбец «b»).
move.col(df, "b", "g")
- Переместите «c» после «e».
move.col(df, "c", "e")
- Переместите «g» перед «a» (т. Е. Сделайте первый столбец «g»).
move.col(df, "g", "a", before=TRUE)
- Переместите «d» и «f» перед «b» (т. Е. Переместите несколько столбцов).
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)])
Вот одна из функций, которая может помочь
- Данные : блок данных
- ColName : имя столбца (столбцов), подлежащего перемещению
- Позиция : номер столбца, в котором вы хотите, чтобы столбец перемещался
moveCol <- function(Data,ColName,Position=1) { D <- dim(Data)[2] DFnames <- names(Data) 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 seq(length(ColName))) { colName <- ColName[i] x <- colName==DFnames if (all(!x)) { warning(paste0('Tag \"', colName, '\" not found')) } else { D1 <- seq(D) D1[x] = Position - 0.5 Data <- Data[order(D1)] } } return(Data) }
@ Дэвид спросил, как переместить «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])]