Перекомпоновка фрейма данных в R - PullRequest
2 голосов
/ 17 июня 2020

У меня есть годовые данные по стране для разных переменных, которые есть в файле CSV. В данных есть много стран и регионов. Ниже приведен простой пример того, как данные выглядят для первых пяти строк.

region   LAM    LAM    LAM    LAM  LAM  LAM 
country  Brazil Brazil Brazil Peru Peru Peru
variable FC     FP     FCO    FC   FP   FCO 
1850     10     20     30     15   25   16  
1851     10     20     30     15   25   16  

После того, как я прочитал файл CSV как фрейм данных в R, я хотел бы преобразовать его, как показано ниже, чтобы сделать с ним легко работать.

region country  year   variable amount
LAM    Brazil   1850    FC     10  
LAM    Brazil   1851    FC     10
LAM    Brazil   1850    FP     20
LAM    Brazil   1850    FP     20
LAM    Brazil   1850    FCO    30 
LAM    Brazil   1850    FCO    30 
LAM    Peru     1850    FC     15 

Кто-нибудь знает, как это проще всего сделать?

Ответы [ 4 ]

1 голос
/ 17 июня 2020
library(data.table)

(df <- fread("
region   LAM    LAM    LAM    LAM  LAM  LAM 
country  Brazil Brazil Brazil Peru Peru Peru
variable FC     FP     FCO    FC   FP   FCO 
1850     10     20     30     15   25   16  
1851     10     20     30     15   25   16",  header = FALSE))

df <- setnames(transpose(df), df[, V1]) # transpose df and set col names, where the first column of df is the var names. 

df <- df[-1, ] # then our df is df without the first row

df_long <- melt(df, id.vars = c("region", "country", "variable"), variable.name = "year", value.name = "amount")

df_long

    region  country variable year amount
1     LAM  Brazil       FC   1850     10
2     LAM  Brazil       FP   1850     20
3     LAM  Brazil      FCO   1850     30
4     LAM    Peru       FC   1850     15
5     LAM    Peru       FP   1850     25
6     LAM    Peru      FCO   1850     16
7     LAM  Brazil       FC   1851     10
8     LAM  Brazil       FP   1851     20
9     LAM  Brazil      FCO   1851     30
10    LAM    Peru       FC   1851     15
11    LAM    Peru       FP   1851     25
12    LAM    Peru      FCO   1851     16

1 голос
/ 17 июня 2020
as_tibble(t(df)) %>%  #Transpose the df
  janitor::row_to_names(1) %>% #put the first row as column names
  pivot_longer(c(`1850`,`1851`),names_to = "date",values_to="value") #pivot the df to make it tidier

Что-то вроде этого дает:

# A tibble: 12 x 5
   region country variable date  value
   <chr>  <chr>   <chr>    <chr> <chr>
 1 LAM    Brazil  FC       1850  10   
 2 LAM    Brazil  FC       1851  10   
 3 LAM    Brazil  FP       1850  20   
 4 LAM    Brazil  FP       1851  20   
 5 LAM    Brazil  FCO      1850  30   
 6 LAM    Brazil  FCO      1851  30   
 7 LAM    Peru    FC       1850  15   
 8 LAM    Peru    FC       1851  15   
 9 LAM    Peru    FP       1850  25   
10 LAM    Peru    FP       1851  25   
11 LAM    Peru    FCO      1850  16   
12 LAM    Peru    FCO      1851  16   

Я загрузил в вашу таблицу read_csv2("your working directory",col_names=F).

0 голосов
/ 18 июня 2020

Я бы создал функцию, подобную одной из следующих. Я перечислил функции от самых быстрых до самых медленных при тестировании файла csv, который при транспонировании дает набор данных из 53 столбцов и 100000 строк. Один из вариантов read_transposed будет быстрее для небольших наборов данных.

Все они используют fread, поэтому убедитесь, что в вашем коде есть library(data.table).

csvtool + fread

csvtool имеет очень быструю операцию transpose, которую затем можно быстро прочитать, используя fread.

fread_csvtool <- function(infile, header = TRUE, ...) {
  fread(cmd = sprintf("cat %s | csvtool transpose - | cat", infile), header = header, ...)
}

fread + дальнейшая обработка (1)

read_transposed_1 <- function(infile) {
  temp <- fread(file = infile, header = FALSE)
  setnames(transpose(temp[, -1]), temp[[1]])[, lapply(.SD, type.convert)]
}

fread + дальнейшая обработка (2)

read_transposed_2 <- function(infile) {
  temp <- lapply(fread(file = infile, sep = "\n", header = FALSE)$V1, function(x) {
    scan(what = "", text = x, sep = ",", quiet = TRUE)
  })
  setnames(setDT(lapply(temp, function(x) type.convert(x[-1L]))),
           vapply(temp, '[', character(1L), 1L))[]
}

После того, как данные были прочитаны, вы можете использовать предпочтительный метод преобразования широкого набора данных в длинный набор данных. Поскольку все это приводит к data.table, я бы предложил:

melt(the_output, id.vars = 1:3)    

DEMO

Пример данных

x <- tempfile(fileext = ".csv")
writeLines(c("region,LAM,LAM,LAM,LAM,LAM,LAM",
             "country,Brazil,Brazil,Brazil,Peru,Peru,Peru",
             "variable,FC,FP,FCO,FC,FP,FCO",
             "1850,10,20,30,15,25,16",
             "1851,10,20,30,15,25,16"), x)

fread_csvtool(x)
##    region country variable 1850 1851
## 1:    LAM  Brazil       FC   10   10
## 2:    LAM  Brazil       FP   20   20
## 3:    LAM  Brazil      FCO   30   30
## 4:    LAM    Peru       FC   15   15
## 5:    LAM    Peru       FP   25   25
## 6:    LAM    Peru      FCO   16   16

melt(fread_csvtool(x), id.vars = 1:3, variable.name = "year", value.name = "amount")
##     region country variable year amount
##  1:    LAM  Brazil       FC 1850     10
##  2:    LAM  Brazil       FP 1850     20
##  3:    LAM  Brazil      FCO 1850     30
##  4:    LAM    Peru       FC 1850     15
##  5:    LAM    Peru       FP 1850     25
##  6:    LAM    Peru      FCO 1850     16
##  7:    LAM  Brazil       FC 1851     10
##  8:    LAM  Brazil       FP 1851     20
##  9:    LAM  Brazil      FCO 1851     30
## 10:    LAM    Peru       FC 1851     15
## 11:    LAM    Peru       FP 1851     25
## 12:    LAM    Peru      FCO 1851     16

Тестовый набор данных большего размера

set.seed(1)
n <- 100001
years <- 50
X1 <- replicate(3, stringi::stri_rand_strings(n, 5), FALSE)
X2 <- replicate(years, runif(n), FALSE)
transposed_data <- data.table(t(cbind(as.data.table(X1), as.data.table(X2))))
transposed_data[, V1 := c(paste0("Var", 1:3), 1850:(1850+years-1))]
fwrite(transposed_data, file = "transposed.csv", col.names = FALSE)

fread_csvtool("transposed.csv")
0 голосов
/ 17 июня 2020

Допустим, ваши данные примерно таковы (как сказал Сотос, полезно поделиться воспроизводимыми примерами):

mm <- matrix(
    c("region", "LAM",    "LAM",    "LAM",    "LAM",  "LAM",  "LAM", 
      "country", "Brazil", "Brazil", "Brazil", "Peru", "Peru", "Peru",
      "variable", "FC",     "FP",     "FCO",    "FC",   "FP",   "FCO", 
      "1850",   10,     20,     30,     15,   25,   16,
      "1851",  10,     20,     30,     15,   25,   16),
    byrow = TRUE,
    ncol = 7)

varnames <- mm[,1]  # to have variable names

mm <- t(mm) # we transpose it

mm <- as.data.frame(mm) # as data frame

colnames(mm) <- varnames # we set variable names

mm <- mm[-1, ] # this first row should not be there, 
               # probably this would be different as you import from a csv

library(tidyr)

mm <- pivot_longer(data = mm,
               cols = c("1850", "1851"),
               names_to = "year",
               values_to = "amount")

Я думаю, это то, что вы ищете

mm
# A tibble: 12 x 5

   region country variable year  amount
   <fct>  <fct>   <fct>    <chr> <fct> 
 1 LAM    Brazil  FC       1850  10    
 2 LAM    Brazil  FC       1851  10    
 3 LAM    Brazil  FP       1850  20    
 4 LAM    Brazil  FP       1851  20    
 5 LAM    Brazil  FCO      1850  30    
 6 LAM    Brazil  FCO      1851  30    
 7 LAM    Peru    FC       1850  15    
 8 LAM    Peru    FC       1851  15    
 9 LAM    Peru    FP       1850  25    
10 LAM    Peru    FP       1851  25    
11 LAM    Peru    FCO      1850  16    
12 LAM    Peru    FCO      1851  16
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...