将一个大的宽格式数据(1982 列)融化成一个长格式,然后在 R 中有效地将其转换回宽格式
Melt a big wide-form data (1982 columns) into a long form and then cast it back to wide form in R efficiently
我有一个格式如下所示的数据集,df
:
# the original data format
df <- data.frame(id = 1:2,
var1.20130101 = 1:2,
var1.20130102 = 6:7,
var2.20130101 = c(NA,1),
var2.20130102 = NA)
df
# id var1.20130101 var1.20130102 var2.20130101 var2.20130102
# 1 1 6 NA NA
# 2 2 7 1 NA
我想要的最终输出是:
df.out <- data.frame(id = c(1, 1, 2, 2),
date = c(20130101, 20130102),
var1 = c(1, 6, 2, 7),
var2 = c(NA, NA, 1, NA))
df.out
# id date var1 var2
# 1 20130101 1 NA
# 1 20130102 6 NA
# 2 20130101 2 1
# 2 20130102 7 NA
希望这能解释我想要执行的实际操作。
实际上,我必须对 24 个 CSV 文件执行此任务。每个文件中大约有 1982 列(和几千行)。
id
列,
- 与
id
列和 对应的列名
- 22 个变量加上三个月的日期(=> 22 * 90 = 1980 列)。
这是我的工作流程:
- 读取数据(使用
read.table
,不知为何fread()
无法读取原始文件)并将每个文件拆分为3个子文件,每个大约450MB。
- 对于每个子文件,阅读
fread()
和melt()
。
- 然后从列名称中提取日期和名称信息。
dcast()
来自 id ~ date + name
。
- 将文件写回 CSV 文件。
这是我正在使用的脚本。我正在寻找更高效和自动化(不拆分文件)的解决方案。
setwd("C:/Users/Administrator/Desktop/chencheng/rawdata")
source("code1.2.R")
file.name <- list.files()
n <- length(file.name)
for (i in 1:n){
fileDispart(file.name[i])
gc(TRUE)
}
setwd("E:/chencheng/step2file")
file.name2 <- list.files()
n <- length(file.name2)
for (i in 1:n){
dataTran(file.name2[i])
gc(TRUE)
}
code1.2.R:
library(reshape2)
library(stringr)
library(data.table)
library(dplyr)
fileDispart <- function(file){
dat <- read.csv(file)
n <- dim(dat)[1]
unit <- 120000
m <- ceiling(n / unit)
start <- 1
file <- gsub('.csv', '', file)
####################################
for(i in 1:m) {
if(i < m) {
end <- i * unit
start <- end + 1
write.csv(dat[start:end, ], paste0(file, i, '.csv'),
quote = F, row.names = F, na = "")
} else {
write.csv(dat[start:n, ], paste0("E:/chencheng/step2file/",
file, "_", i, '.csv'), quote = F, row.names = F, na = "")
}
}
}
dataTran <- function(pathin = "") {
pathout = "E:/chencheng/"
# dat <- fread("e:/chencheng/step2file/2013Q1p2_3.csv")
if(length(pathin) == 0 | length(pathout) == 0) stop("Wrong parameters!")
dat <- fread(pathin)
n <- dim(dat)[2]
dat <- dat %>% select(-2) # remove the extra column,
# just chinese names of the id
dat.m <- melt(dat, id = 1)
rm(dat)
gc()
name <- as.character(dat.m$variable)
name.len <- nchar(name)
dat.m$name <- str_sub(name, 1, name.len - 8)
dat.m$date <- str_sub(name, name.len - 7, name.len)
names(dat.m)[1] <- 'id'
dat.m <- dat.m %>% select(-2)
dat.m <- dcast.data.table(dat.m, id + date ~ name, identity)
# write the file
filename <- gsub('.csv', '', pathin)
write.csv(dat.m, paste0(pathout, filename, '.csv'),
quote = F, row.names = F, na = "")
}
此外,我使用的服务器是 64G RAM (windows server 2008)。 R 和 SQL 服务器是我完成此任务的仅有的两个选项;也许一点 python 就可以了。
没有数据样本很难解决这样的问题,但应该可以进行一些明显的优化。
不确定它是否加速很多但你可以尝试不存储中间数据并使用 data.table 链接
dataTran <- function(pathin = ""){
# ...
dat.m <- fread(pathin)[,-2L,with=FALSE
][,melt(.SD, id=1:2, measure=3)]
# ...
# likely the following are redundant: rm(dat); gc()
# ...
# as.character, nchar, str_sub - likely those can be also speedup
# ...
filename <- gsub('.csv', '', pathin)
dat.m[,-2L,with=FALSE
][,dcast.data.table(.SD, id + date ~ name, identity)
][,write.csv(.SD, paste0(pathout, filename, '.csv'), quote = F, row.names = F, na = "")]
}
我有一个格式如下所示的数据集,df
:
# the original data format
df <- data.frame(id = 1:2,
var1.20130101 = 1:2,
var1.20130102 = 6:7,
var2.20130101 = c(NA,1),
var2.20130102 = NA)
df
# id var1.20130101 var1.20130102 var2.20130101 var2.20130102
# 1 1 6 NA NA
# 2 2 7 1 NA
我想要的最终输出是:
df.out <- data.frame(id = c(1, 1, 2, 2),
date = c(20130101, 20130102),
var1 = c(1, 6, 2, 7),
var2 = c(NA, NA, 1, NA))
df.out
# id date var1 var2
# 1 20130101 1 NA
# 1 20130102 6 NA
# 2 20130101 2 1
# 2 20130102 7 NA
希望这能解释我想要执行的实际操作。
实际上,我必须对 24 个 CSV 文件执行此任务。每个文件中大约有 1982 列(和几千行)。
id
列,- 与
id
列和 对应的列名
- 22 个变量加上三个月的日期(=> 22 * 90 = 1980 列)。
这是我的工作流程:
- 读取数据(使用
read.table
,不知为何fread()
无法读取原始文件)并将每个文件拆分为3个子文件,每个大约450MB。 - 对于每个子文件,阅读
fread()
和melt()
。 - 然后从列名称中提取日期和名称信息。
dcast()
来自id ~ date + name
。- 将文件写回 CSV 文件。
这是我正在使用的脚本。我正在寻找更高效和自动化(不拆分文件)的解决方案。
setwd("C:/Users/Administrator/Desktop/chencheng/rawdata")
source("code1.2.R")
file.name <- list.files()
n <- length(file.name)
for (i in 1:n){
fileDispart(file.name[i])
gc(TRUE)
}
setwd("E:/chencheng/step2file")
file.name2 <- list.files()
n <- length(file.name2)
for (i in 1:n){
dataTran(file.name2[i])
gc(TRUE)
}
code1.2.R:
library(reshape2)
library(stringr)
library(data.table)
library(dplyr)
fileDispart <- function(file){
dat <- read.csv(file)
n <- dim(dat)[1]
unit <- 120000
m <- ceiling(n / unit)
start <- 1
file <- gsub('.csv', '', file)
####################################
for(i in 1:m) {
if(i < m) {
end <- i * unit
start <- end + 1
write.csv(dat[start:end, ], paste0(file, i, '.csv'),
quote = F, row.names = F, na = "")
} else {
write.csv(dat[start:n, ], paste0("E:/chencheng/step2file/",
file, "_", i, '.csv'), quote = F, row.names = F, na = "")
}
}
}
dataTran <- function(pathin = "") {
pathout = "E:/chencheng/"
# dat <- fread("e:/chencheng/step2file/2013Q1p2_3.csv")
if(length(pathin) == 0 | length(pathout) == 0) stop("Wrong parameters!")
dat <- fread(pathin)
n <- dim(dat)[2]
dat <- dat %>% select(-2) # remove the extra column,
# just chinese names of the id
dat.m <- melt(dat, id = 1)
rm(dat)
gc()
name <- as.character(dat.m$variable)
name.len <- nchar(name)
dat.m$name <- str_sub(name, 1, name.len - 8)
dat.m$date <- str_sub(name, name.len - 7, name.len)
names(dat.m)[1] <- 'id'
dat.m <- dat.m %>% select(-2)
dat.m <- dcast.data.table(dat.m, id + date ~ name, identity)
# write the file
filename <- gsub('.csv', '', pathin)
write.csv(dat.m, paste0(pathout, filename, '.csv'),
quote = F, row.names = F, na = "")
}
此外,我使用的服务器是 64G RAM (windows server 2008)。 R 和 SQL 服务器是我完成此任务的仅有的两个选项;也许一点 python 就可以了。
没有数据样本很难解决这样的问题,但应该可以进行一些明显的优化。
不确定它是否加速很多但你可以尝试不存储中间数据并使用 data.table 链接
dataTran <- function(pathin = ""){
# ...
dat.m <- fread(pathin)[,-2L,with=FALSE
][,melt(.SD, id=1:2, measure=3)]
# ...
# likely the following are redundant: rm(dat); gc()
# ...
# as.character, nchar, str_sub - likely those can be also speedup
# ...
filename <- gsub('.csv', '', pathin)
dat.m[,-2L,with=FALSE
][,dcast.data.table(.SD, id + date ~ name, identity)
][,write.csv(.SD, paste0(pathout, filename, '.csv'), quote = F, row.names = F, na = "")]
}