Элегантный способ добавления столбцов в определенную позицию во фрейме данных

У меня есть data.frame с 3 столбцами: дата, ставка, цена. Я хочу добавить столбцы, которые поступают из матрицы, после ставки и до цены.

df = tibble('date' = c('01/01/2000', '02/01/2000', '03/01/2000'),
        'rate' = c(7.50, 6.50, 5.54),
        'price' = c(92, 94, 96))

Я вычислил лаги скорости, используя функцию, которая выводит матрицу:

rate_Lags = matrix(data = c(NA, 7.50, 5.54, NA, NA, 7.50), ncol=2, dimnames=list(c(), c('rate_tMinus1', 'rate_tMinus2'))

Я хочу вставить эти запаздывания после курса (и до цены), используя индексирование имен, а не порядок столбцов.

Функция add_column из пакета tibble (Добавление столбца между двумя columns in a data.frame) не работает, потому что он принимает только атомарный вектор (следовательно, если у меня есть 10 задержек, мне придется вызывать add_column 10 раз). Я мог бы использовать apply в моей rate_Lags матрице. Однако затем я теряю dimnames из моей rate_Lags матрицы.

Использование индексации номеров (подмножество) (https://stat.ethz.ch/pipermail/r-help/2011-August/285534.html) мог бы работать, если бы я знал позицию определенного имени столбца (любая функция, которая извлекает позицию имени столбца?).

Есть ли простой способ вставить группу столбцов s в определенную позицию в объекте фрейма данных / тиббла?


person Emiliano A. Carlevaro    schedule 19.06.2018    source источник


Ответы (3)


Вы можете упустить из виду следующее

library(dplyr)
I <- which(names(df) == "rate")
if (I == ncol(df)) {
    cbind(df, rate_Lags)
} else {
    cbind(select(df, 1:I), rate_Lags, select(df, (I+1):ncol(df))) 
}

#     date rate rate_tMinus1 rate_tMinus2 price
# 1 0.0005 7.50           NA           NA    92
# 2 0.0010 6.50         7.50           NA    94
# 3 0.0015 5.54         5.54          7.5    96
person CPak    schedule 19.06.2018
comment
Я отредактировал вопрос. В определении df была ошибка: OP записал 01/01/2000 и т.д., которые представляют собой последовательности делений, дающих 0.0005 и т.д., хотя, очевидно, это должны быть даты. - person Rui Barradas; 19.06.2018

Возможно, это не очень элегантно, но вы вызываете функцию только один раз, и я считаю, что это более или менее универсальное назначение.

fun <- function(DF, M){
  nms_DF <- colnames(DF)
  nms_M <- colnames(M)
  inx <- which(sapply(nms_DF, function(x) length(grep(x, nms_M)) > 0))
  cbind(DF[seq_len(inx)], M, DF[ seq_along(nms_DF)[-seq_len(inx)] ])
}

fun(df, rate_Lags)
#        date rate rate_tMinus1 rate_tMinus2 price
#1 01/01/2000 7.50           NA           NA    92
#2 02/01/2000 6.50         7.50           NA    94
#3 03/01/2000 5.54         5.54          7.5    96
person Rui Barradas    schedule 19.06.2018
comment
Я думаю, вы можете еще больше упростить эту логику - например, idx <- seq.int(1L,match("rate",names(df))) и cbind(df[idx], rate_Lags, df[-(idx)]). - person thelatemail; 19.06.2018
comment
@thelatemail Да, вы правы, но как бы то ни было, мне не нужно знать имя столбца, который нужно сопоставить. Вот почему я подумал о grep. Это сложнее, но sapply цикл над атрибутом colnames не должен занимать много времени. - person Rui Barradas; 19.06.2018

Мы могли бы unclass набор данных в list, а затем использовать append для вставки 'rate_Lags' в определенных местах, повторно преобразовать list в data.frame

i1 <- match('rate', names(df))
data.frame(append(unclass(df), as.data.frame(rate_Lags), after = i1))
#        date rate rate_tMinus1 rate_tMinus2 price
#1 01/01/2000 7.50           NA           NA    92
#2 02/01/2000 6.50         7.50           NA    94
#3 03/01/2000 5.54         5.54          7.5    96

Или с tidyverse

library(tidyverse)
rate_Lags %>%
       as_tibble %>%
       append(unclass(df), ., after = i1) %>% 
       bind_cols
# A tibble: 3 x 5
#  date        rate rate_tMinus1 rate_tMinus2 price
#  <chr>      <dbl>        <dbl>        <dbl> <dbl>
#1 01/01/2000  7.5         NA            NA      92
#2 02/01/2000  6.5          7.5          NA      94
#3 03/01/2000  5.54         5.54          7.5    96
person akrun    schedule 19.06.2018
comment
Простое решение и не требует библиотеки. Единственный недостаток - я не знаю, в какую позицию вставить столбец (в данном случае after = 2). Это можно решить с помощью which(names(df) = 'rate'). - person Emiliano A. Carlevaro; 19.06.2018
comment
@ EmilianoA.Carlevaro или используйте match('rate', names(df)) - person akrun; 19.06.2018
comment
В dplyr также есть add_column() функция - person meriops; 19.06.2018
comment
@meriops Да, он есть, но его можно было бы добавить в data.frame, а у OP есть несколько столбцов для добавления вместо одного - person akrun; 19.06.2018
comment
ой, я пропустил это, извините. Тогда можно было бы быстро и грязно извлечь дату в df1, а ставку и цену в df2, а затем связать столбцы df1, столбцы для вставки и df2 ... - person meriops; 20.06.2018