У меня есть два фрейма данных f1 и f2.
row11 <- c("a", "c", "2000", "2001", "2005")
row12 <- c("", "", 7, 10, 15)
f1 <- as.data.frame(rbind(row11, row12))
row21 <- c("a", "b", "c", "2002", "2005")
row22 <- c("", "", "", 1, 15)
f2 <- as.data.frame(rbind(row21, row22))
Я хотел бы связать эти два фрейма данных таким образом, чтобы получить фрейм данных f3:
row31 <- c("a", "b", "c", seq(2000,2005,1))
row32 <- c("", "", "", 7, 10, NA, NA, NA, 15)
row33 <- c("", "", "", NA, NA, 1, NA, NA, 15)
f3 <- rbind(row32, row33)
colnames(f3) <- row31
ф3:
a b c 2000 2001 2002 2003 2004 2005
row32 "" "" "" "7" "10" NA NA NA "15"
row33 "" "" "" NA NA "1" NA NA "15"
f3 берет имена столбцов «a», «b» и «c» и добавляет временной ряд с 2000 по 2005 год с соответствующими значениями из f1 и f2.
Я бы предпочел решение с dplyr.





Вы можете попробовать следующее (в основном) решение dplyr, которое определяет вспомогательную функцию для привязки строк после переименования и удаления первой строки, а затем упорядочивает столбцы.
Я уверен, что есть более элегантный способ: я использую небольшую букву R для определения столбцов с отсутствующим годом, а затем возвращаюсь к tidyverse, чтобы добавить новые столбцы и изменить их порядок:
# helper function
f <- function(x){
x %>%
setNames(unlist(x[1,])) %>%
slice(-1)
}
# combine all dfs
f3_temp <- list(f1, f2) %>%
purrr::map(f) %>%
bind_rows()
# Note, if all your data frames contain the pattern "f" followed by numbers,
# you could replace `list(f1, f2) %>% ... with:
f3_temp <- mget(ls(pattern = "f\\d+")) %>%
purrr::map(f) %>%
bind_rows()
# Identify in missing years in column names
num_names <- as.numeric(names(f3_temp))[!is.na(as.numeric(names(f3_temp)))]
new_names <- setdiff(seq(min(num_names), max(num_names), 1L), names(f3_temp))
# Add in new and reorder all columns:
f3 <- f3_temp %>%
tibble::add_column(!!!new_names) %>%
mutate(across(as.character(new_names), ~ NA)) %>%
select(order(nchar(colnames(.)), colnames(.)))
Выход:
# a b c 2000 2001 2002 2003 2004 2005
# row12 7 10 <NA> NA NA 15
# row22 <NA> <NA> 1 NA NA 15
Большое спасибо! Как я могу адаптировать первую часть кода, если у меня есть не только два кадра данных, но и n, скажем, f1, f2, ..., fn?
Привет @MPB_2022 — см. редактирование — вы можете объединить их в список и использовать purrr::map, чтобы применить вспомогательную функцию ко всем фреймам данных.
Простой подход для создания двух фреймов данных из фреймов данных row1 и row2, а затем их связывания с помощью dplyr.
Я транспонирую (t(...)) два вектора-строки, row12 и row22, потому что data.frame ожидает входные данные столбца, а не векторные входные данные.
Транспонирование атомарного вектора создает матрицу, которую можно использовать для ввода data.frame.
row11 <- c("a", "c", "2000", "2001", "2005")
row12 <- c("", "", 7, 10, 15)
row21 <- c("a", "b", "c", "2002", "2005")
row22 <- c("", "", "", 1, 15)
f1 <- data.frame(t(row12))
colnames(f1)<- row11
f2 <- data.frame(t(row22))
colnames(f2) <- row21
f3 <- dplyr::bind_rows(f1, f2)
Затем вывод f3 приведен ниже. Вы можете изменить порядок столбцов и преобразовать numeric в character, если это необходимо.
> f3
a c 2000 2001 2005 b 2002
1 7 10 15 <NA> <NA>
2 <NA> <NA> 15 1
И демонстрация вывода транспонирования атомного вектора:
> t(row12)
[,1] [,2] [,3] [,4] [,5]
[1,] "" "" "7" "10" "15"
> t(row12) |> class()
[1] "matrix" "array"
Другой вариант :
### Packages
library(dplyr)
library(tibble)
library(janitor)
### Data
row11 <- c("a", "c", "2000", "2001", "2005")
row12 <- c("", "", 7, 10, 15)
df1 <- data.frame(rbind(row11, row12))
row21 <- c("a", "b", "c", "2002", "2005")
row22 <- c("", "", "", 1, 15)
df2 <- data.frame(rbind(row21, row22))
### Promote the first rows to colnames
df1=row_to_names(df1,1)
df2=row_to_names(df2,1)
### Merge all dataframes and get the lowest and highest value for year
### You can add all your dataframes in the bind_rows step
mrg=bind_rows(df1,df2)
m1=min(as.numeric(colnames(mrg)),na.rm = TRUE)
m2=max(as.numeric(colnames(mrg)),na.rm = TRUE)
### Build a null row data frame with the missing years
newcols=setNames(rep('', length(seq.int(m1,m2))), seq.int(m1,m2))
ndf=tibble(.rows = 0) %>% add_column(!!!newcols)
### Bind it with the first one
output=bind_rows(mrg,ndf)
### Reorder the columns and type them correctly
out=output %>%
select(sort(colnames(.)[!grepl("[0-9]",colnames(.))]),
sort(colnames(.)[grepl("[0-9]",colnames(.))])) %>%
mutate(across(colnames(.)[grepl("[0-9]",colnames(.))][1]:last_col(),~as.numeric(.)))
Выход :
a b c 2000 2001 2002 2003 2004 2005
row12 <NA> 7 10 NA NA NA 15
row22 NA NA 1 NA NA 15
Н.Б. : row12 содержит «NA» в столбце B (отсутствует в исходном сообщении). При необходимости его можно было легко заменить.
Не используйте
as.data.frame(rbind(...)), потому чтоrbindсоздает матрицу и, следовательно, все значения приводятся к символу класса. Используйтеdata.frame(...)напрямую.