여러 .csv 파일을 한 번에 가져오는 방법은 무엇입니까?
여러 개의 data.csv 파일이 들어 있는 폴더가 있다고 가정합니다. 각각의 파일에는 동일한 수의 변수가 있지만 각각 다른 시간의 변수가 포함되어 있습니다.R에서는 개별적으로 모두 수입하지 않고 동시에 수입할 수 있는 방법이 있습니까?
문제는 가져올 데이터 파일이 약 2,000개 있으며 코드만 사용하여 개별적으로 가져와야 한다는 것입니다.
read.delim(file="filename", header=TRUE, sep="\t")
그다지 효율적이지 않습니다.
다음과 같은 것이 각 데이터 프레임을 단일 목록의 개별 요소로 만들어야 합니다.
temp = list.files(pattern="*.csv")
myfiles = lapply(temp, read.delim)
가 단일 디렉토리)에 CSV의 합니다..csv
.
이러한 프레임으로 하십시오.do.call(rbind,...)
,dplyr::bind_rows()
또는data.table::rbindlist()
.
이 각각의 객체에 , 권장되지 , 할 수 있습니다.assign
:
temp = list.files(pattern="*.csv")
for (i in 1:length(temp)) assign(temp[i], read.csv(temp[i]))
는또 없이, 이없.assign
( 이름을 정리하는 .list2env
다음을 시도할 수 있습니다.
temp = list.files(pattern="*.csv")
list2env(
lapply(setNames(temp, make.names(gsub("*.csv$", "", temp))),
read.csv), envir = .GlobalEnv)
하지만 다시 말하지만, 종종 그들을 하나의 목록에 두는 것이 더 낫습니다.
한 르고간결한빠.tidyverse
솔루션: (Base R보다 2배 이상 빠름) read.csv
)
tbl <-
list.files(pattern = "*.csv") %>%
map_df(~read_csv(.))
그리고 data.table은 이러한 로드 시간을 다시 절반으로 줄일 수 있습니다.(기본 R의 1/4회)
library(data.table)
tbl_fread <-
list.files(pattern = "*.csv") %>%
map_df(~fread(.))
인수는 데이터 프레임 인자를 자유롭게 유지합니다(그리고 마벨이 지적했듯이).fread
)
수 .col_types
논쟁.
tbl <-
list.files(pattern = "*.csv") %>%
map_df(~read_csv(., col_types = cols(.default = "c")))
하위 디렉터리로 이동하여 최종적으로 바인딩할 파일 목록을 구성하려면 경로 이름을 포함하고 파일을 전체 이름으로 목록에 등록해야 합니다.이렇게 하면 현재 디렉터리 외부에서 바인딩 작업을 계속할 수 있습니다. (전체 경로 이름을 디렉터리 '경계'를 통해 다시 이동할 수 있도록 여권처럼 작동하는 것으로 간주)
tbl <-
list.files(path = "./subdirectory/",
pattern = "*.csv",
full.names = T) %>%
map_df(~read_csv(., col_types = cols(.default = "c")))
Hadley가 여기서 설명한 것처럼 (약 절반 아래):
map_df(x, f)
와실적동로다니일합으질다▁effect▁as와 같습니다.do.call("rbind", lapply(x, f))
....
보너스 기능 - 아래 설명에서 Niks 기능 요청별로 레코드에 파일 이름을 추가합니다.filename
매 기록마다
코드 설명: 테이블을 처음 읽는 동안 각 레코드에 파일 이름을 추가하는 기능을 만듭니다.그런 다음 단순한 기능 대신 해당 기능을 사용합니다.read_csv()
기능.
read_plus <- function(flnm) {
read_csv(flnm) %>%
mutate(filename = flnm)
}
tbl_with_sources <-
list.files(pattern = "*.csv",
full.names = T) %>%
map_df(~read_plus(.))
(타이프캐스팅 및 하위 디렉토리 처리 접근 방식은 내부에서 처리할 수도 있습니다.read_plus()
위에서 제시한 두 번째 및 세 번째 변형 모델에서 설명한 것과 동일한 방식으로 작동합니다.)
### Benchmark Code & Results
library(tidyverse)
library(data.table)
library(microbenchmark)
### Base R Approaches
#### Instead of a dataframe, this approach creates a list of lists
#### removed from analysis as this alone doubled analysis time reqd
# lapply_read.delim <- function(path, pattern = "*.csv") {
# temp = list.files(path, pattern, full.names = TRUE)
# myfiles = lapply(temp, read.delim)
# }
#### `read.csv()`
do.call_rbind_read.csv <- function(path, pattern = "*.csv") {
files = list.files(path, pattern, full.names = TRUE)
do.call(rbind, lapply(files, function(x) read.csv(x, stringsAsFactors = FALSE)))
}
map_df_read.csv <- function(path, pattern = "*.csv") {
list.files(path, pattern, full.names = TRUE) %>%
map_df(~read.csv(., stringsAsFactors = FALSE))
}
### *dplyr()*
#### `read_csv()`
lapply_read_csv_bind_rows <- function(path, pattern = "*.csv") {
files = list.files(path, pattern, full.names = TRUE)
lapply(files, read_csv) %>% bind_rows()
}
map_df_read_csv <- function(path, pattern = "*.csv") {
list.files(path, pattern, full.names = TRUE) %>%
map_df(~read_csv(., col_types = cols(.default = "c")))
}
### *data.table* / *purrr* hybrid
map_df_fread <- function(path, pattern = "*.csv") {
list.files(path, pattern, full.names = TRUE) %>%
map_df(~fread(.))
}
### *data.table*
rbindlist_fread <- function(path, pattern = "*.csv") {
files = list.files(path, pattern, full.names = TRUE)
rbindlist(lapply(files, function(x) fread(x)))
}
do.call_rbind_fread <- function(path, pattern = "*.csv") {
files = list.files(path, pattern, full.names = TRUE)
do.call(rbind, lapply(files, function(x) fread(x, stringsAsFactors = FALSE)))
}
read_results <- function(dir_size){
microbenchmark(
# lapply_read.delim = lapply_read.delim(dir_size), # too slow to include in benchmarks
do.call_rbind_read.csv = do.call_rbind_read.csv(dir_size),
map_df_read.csv = map_df_read.csv(dir_size),
lapply_read_csv_bind_rows = lapply_read_csv_bind_rows(dir_size),
map_df_read_csv = map_df_read_csv(dir_size),
rbindlist_fread = rbindlist_fread(dir_size),
do.call_rbind_fread = do.call_rbind_fread(dir_size),
map_df_fread = map_df_fread(dir_size),
times = 10L)
}
read_results_lrg_mid_mid <- read_results('./testFolder/500MB_12.5MB_40files')
print(read_results_lrg_mid_mid, digits = 3)
read_results_sml_mic_mny <- read_results('./testFolder/5MB_5KB_1000files/')
read_results_sml_tny_mod <- read_results('./testFolder/5MB_50KB_100files/')
read_results_sml_sml_few <- read_results('./testFolder/5MB_500KB_10files/')
read_results_med_sml_mny <- read_results('./testFolder/50MB_5OKB_1000files')
read_results_med_sml_mod <- read_results('./testFolder/50MB_5OOKB_100files')
read_results_med_med_few <- read_results('./testFolder/50MB_5MB_10files')
read_results_lrg_sml_mny <- read_results('./testFolder/500MB_500KB_1000files')
read_results_lrg_med_mod <- read_results('./testFolder/500MB_5MB_100files')
read_results_lrg_lrg_few <- read_results('./testFolder/500MB_50MB_10files')
read_results_xlg_lrg_mod <- read_results('./testFolder/5000MB_50MB_100files')
print(read_results_sml_mic_mny, digits = 3)
print(read_results_sml_tny_mod, digits = 3)
print(read_results_sml_sml_few, digits = 3)
print(read_results_med_sml_mny, digits = 3)
print(read_results_med_sml_mod, digits = 3)
print(read_results_med_med_few, digits = 3)
print(read_results_lrg_sml_mny, digits = 3)
print(read_results_lrg_med_mod, digits = 3)
print(read_results_lrg_lrg_few, digits = 3)
print(read_results_xlg_lrg_mod, digits = 3)
# display boxplot of my typical use case results & basic machine max load
par(oma = c(0,0,0,0)) # remove overall margins if present
par(mfcol = c(1,1)) # remove grid if present
par(mar = c(12,5,1,1) + 0.1) # to display just a single boxplot with its complete labels
boxplot(read_results_lrg_mid_mid, las = 2, xlab = "", ylab = "Duration (seconds)", main = "40 files @ 12.5MB (500MB)")
boxplot(read_results_xlg_lrg_mod, las = 2, xlab = "", ylab = "Duration (seconds)", main = "100 files @ 50MB (5GB)")
# generate 3x3 grid boxplots
par(oma = c(12,1,1,1)) # margins for the whole 3 x 3 grid plot
par(mfcol = c(3,3)) # create grid (filling down each column)
par(mar = c(1,4,2,1)) # margins for the individual plots in 3 x 3 grid
boxplot(read_results_sml_mic_mny, las = 2, xlab = "", ylab = "Duration (seconds)", main = "1000 files @ 5KB (5MB)", xaxt = 'n')
boxplot(read_results_sml_tny_mod, las = 2, xlab = "", ylab = "Duration (milliseconds)", main = "100 files @ 50KB (5MB)", xaxt = 'n')
boxplot(read_results_sml_sml_few, las = 2, xlab = "", ylab = "Duration (milliseconds)", main = "10 files @ 500KB (5MB)",)
boxplot(read_results_med_sml_mny, las = 2, xlab = "", ylab = "Duration (microseconds) ", main = "1000 files @ 50KB (50MB)", xaxt = 'n')
boxplot(read_results_med_sml_mod, las = 2, xlab = "", ylab = "Duration (microseconds)", main = "100 files @ 500KB (50MB)", xaxt = 'n')
boxplot(read_results_med_med_few, las = 2, xlab = "", ylab = "Duration (seconds)", main = "10 files @ 5MB (50MB)")
boxplot(read_results_lrg_sml_mny, las = 2, xlab = "", ylab = "Duration (seconds)", main = "1000 files @ 500KB (500MB)", xaxt = 'n')
boxplot(read_results_lrg_med_mod, las = 2, xlab = "", ylab = "Duration (seconds)", main = "100 files @ 5MB (500MB)", xaxt = 'n')
boxplot(read_results_lrg_lrg_few, las = 2, xlab = "", ylab = "Duration (seconds)", main = "10 files @ 50MB (500MB)")
중간 사용 사례
더 큰 사용 사례
다양한 사용 사례
수 ": 파일 수(1000, 100, 10)"
크기 최종데프레크기 (5MB, 50MB, 500MB)
크기를 를 클릭하십시오).
기본 R 결과는 purrr과 dplyr의 C 라이브러리를 가져오는 오버헤드가 더 큰 규모의 처리 작업을 수행할 때 관찰되는 성능 이득을 초과하는 최소 사용 사례에 더 좋습니다.
만약 당신이 당신 자신의 테스트를 실행하고 싶다면, 당신은 이 bash 스크립트가 도움이 될 것입니다.
for ((i=1; i<=$2; i++)); do
cp "$1" "${1:0:8}_${i}.csv";
done
bash what_you_name_this_script.sh "fileName_you_want_copied" 100
파일 이름의 처음 8자와 밑줄 뒤에 순차적으로 번호가 매겨진 100개의 파일 복사본을 만듭니다.
귀인 및 감사
특별한 감사를 표합니다.
- Tyler Lincer와 Akrun은 마이크로 벤치마크를 시연했습니다.
- 씨를 감사합니다.
map_df()
여기에 - David McLaughlin은 시각화를 개선하고 작은 파일, 작은 데이터 프레임 분석 결과에서 관찰된 성능 반전에 대해 논의/확인하는 데 도움이 되는 피드백을 제공합니다.
- 가는마벨키의 기본 을 가리키는
fread()
(저는 더 자세히 공부해야 합니다.data.table
.)
다음은 R base를 사용하여 .csv 파일을 하나의 data.frame으로 변환하는 몇 가지 옵션과 R에서 파일을 읽는 데 사용할 수 있는 일부 패키지입니다.
이 속도는 아래 옵션보다 느립니다.
# Get the files names
files = list.files(pattern="*.csv")
# First apply read.csv, then rbind
myfiles = do.call(rbind, lapply(files, function(x) read.csv(x, stringsAsFactors = FALSE)))
편집: - 다음을 사용하여 몇 가지 추가 선택 가능data.table
그리고.readr
A fread()
의 data.table
꾸러미이것은 R에서 가장 빠른 옵션입니다.
library(data.table)
DT = do.call(rbind, lapply(files, fread))
# The same using `rbindlist`
DT = rbindlist(lapply(files, fread))
csv 파일을 읽기 위한 또 다른 패키지인 reader를 사용합니다.보다 느립니다.fread
기본 R보다 빠르지만 기능이 다릅니다.
library(readr)
library(dplyr)
tbl = lapply(files, read_csv) %>% bind_rows()
많은 파일과 많은 코어로 인해fread xargs cat
(아래 설명)는 상위 3개 답변에서 가장 빠른 솔루션보다 약 50배 더 빠릅니다.
rbindlist lapply read.delim 500s <- 1st place & accepted answer
rbindlist lapply fread 250s <- 2nd & 3rd place answers
rbindlist mclapply fread 10s
fread xargs cat 5s
121401 csvs를 단일 data.table로 읽는 시간입니다.각 시간은 평균 3회 런 후 반올림됩니다.각 csv에는 3개의 열, 1개의 헤더 행 및 평균적으로 4.510개의 행이 있습니다.시스템은 96개의 코어가 있는 GCP VM입니다.
@A5C1D2H2I1M1N2O1R2T1, @leerssej @marbel @marbel 상 3 개답기또으니다로적동합본일은를각를결과파일에변나의는적다다용.delim(읽기.delim) 한rbind/rbindlist열 data.table. 데이터 세트의 를 합니다.rbindlist(lapply(list.files("*.csv"),fread))
데이터셋의 하는데, form이 . 중간 크기의 데이터셋의 경우 lapply 대신 parallel의 mclapply를 사용하는데, 이는 코어가 많으면 훨씬 빠릅니다.
이것은 다른 R-내부 대안보다 낫지만, 속도가 중요할 때 많은 수의 소형 csvs에 대해서는 최선이 아닙니다.이 경우 처음 사용하는 것이 훨씬 빠를 수 있습니다.cat
@Spacedman의 대답처럼 모든 csv를 하나의 csv로 연결합니다.R 내에서 이 작업을 수행하는 방법에 대한 자세한 내용을 추가합니다.
x = fread(cmd='cat *.csv', header=F)
그러나 각 csv에 헤더가 있으면 어떻게 합니까?
x = fread(cmd="awk 'NR==1||FNR!=1' *.csv", header=T)
그리고 만약 당신이 너무 많은 파일을 가지고 있다면 어떨까요?*.csv
쉘글로브 실패?
x = fread(cmd='find . -name "*.csv" | xargs cat', header=F)
그리고 모든 파일에 헤더가 있고 파일이 너무 많으면 어떻게 합니까?
header = fread(cmd='find . -name "*.csv" | head -n1 | xargs head -n1', header=T)
x = fread(cmd='find . -name "*.csv" | xargs tail -q -n+2', header=F)
setnames(x,header)
연결된 CSV가 시스템 메모리에 비해 너무 크면 어떻게 됩니까? (예: /dev/shm 공간 부족 오류)
system('find . -name "*.csv" | xargs cat > combined.csv')
x = fread('combined.csv', header=F)
머리글로?
system('find . -name "*.csv" | head -n1 | xargs head -n1 > combined.csv')
system('find . -name "*.csv" | xargs tail -q -n+2 >> combined.csv')
x = fread('combined.csv', header=T)
마지막으로 디렉토리에 모든 .csv를 저장하지 않고 특정 파일 집합을 저장하려면 어떻게 해야 합니까? (또한 모든 파일에 헤더가 있습니다.) (이것은 제 사용 사례입니다.)
fread(text=paste0(system("xargs cat|awk 'NR==1||$1!=\"<column one name>\"'",input=paths,intern=T),collapse="\n"),header=T,sep="\t")
그리고 이것은 플레인 스프레드 xargs 고양이와 거의 같은 속도입니다 :)
data9월 의 경우, "": data.table v1.11.6" (2018년 9월 19일) ""를 합니다.cmd=
fread(cmd=
.
요약하자면, 속도에 관심이 있고 파일과 코어가 많은 경우 fread xargs cat은 상위 3개 답변에서 가장 빠른 솔루션보다 약 50배 더 빠릅니다.
업데이트: 가장 빠른 솔루션을 쉽게 적용하기 위해 작성한 기능이 있습니다.저는 여러 상황에서 생산에 사용하지만, 신뢰하기 전에 자신의 데이터로 철저히 테스트해야 합니다.
fread_many = function(files,header=T,...){
if(length(files)==0) return()
if(typeof(files)!='character') return()
files = files[file.exists(files)]
if(length(files)==0) return()
tmp = tempfile(fileext = ".csv")
# note 1: requires awk, not cat or tail because some files have no final newline
# note 2: parallel --xargs is 40% slower
# note 3: reading to var is 15% slower and crashes R if the string is too long
# note 4: shorter paths -> more paths per awk -> fewer awks -> measurably faster
# so best cd to the csv dir and use relative paths
if(header==T){
system(paste0('head -n1 ',files[1],' > ',tmp))
system(paste0("xargs awk 'FNR>1' >> ",tmp),input=files)
} else {
system(paste0("xargs awk '1' > ",tmp),input=files)
}
DT = fread(file=tmp,header=header,...)
file.remove(tmp)
DT
}
업데이트 2: 여기 결과 data.table에 각 csv의 경로 내 열을 포함시킬 경우를 위한 fread_many 함수의 더 복잡한 버전이 있습니다.이 경우 sep 인수를 사용하여 csv 구분자도 명시적으로 지정해야 합니다.
fread_many = function(files,header=T,keep_inpath=F,sep="auto",...){
if(length(files)==0) return()
if(typeof(files)!='character') return()
files = files[file.exists(files)]
if(length(files)==0) return()
tmp = tempfile(fileext = ".csv")
if(keep_inpath==T){
stopifnot(sep!="auto")
if(header==T){
system(paste0('/usr/bin/echo -ne inpath"',sep,'" > ',tmp))
system(paste0('head -n1 ',files[1],' >> ',tmp))
system(paste0("xargs awk -vsep='",sep,"' 'BEGIN{OFS=sep}{if(FNR>1)print FILENAME,$0}' >> ",tmp),input=files)
} else {
system(paste0("xargs awk -vsep='",sep,"' 'BEGIN{OFS=sep}{print FILENAME,$0}' > ",tmp),input=files)
}
} else {
if(header==T){
system(paste0('head -n1 ',files[1],' > ',tmp))
system(paste0("xargs awk 'FNR>1' >> ",tmp),input=files)
} else {
system(paste0("xargs awk '1' > ",tmp),input=files)
}
}
DT = fread(file=tmp,header=header,sep=sep,...)
file.remove(tmp)
DT
}
주의: csvs를 읽기 전에 연결하는 모든 솔루션은 모두 동일한 구분 기호를 가지고 있다고 가정합니다.모든 csvs가 동일한 구분 기호를 사용하지 않는 경우 대신 rbindlist lapply fread, rbindlist mclapply fread 또는 fread xargs cat을 사용합니다. 여기서 배치의 모든 csvs는 동일한 구분 기호를 사용합니다.
사용하는 것뿐만 아니라lapply
또는 R의 다른 루프 구조를 사용하여 CSV 파일을 하나의 파일로 병합할 수 있습니다.
유닉스에서 파일에 헤더가 없으면 다음과 같이 쉽습니다.
cat *.csv > all.csv
또는 헤더가 있고 헤더와 헤더만 일치하는 문자열을 찾을 수 있는 경우(예: 헤더 행이 모두 "Age"로 시작한다고 가정) 다음 작업을 수행합니다.
cat *.csv | grep -v ^Age > all.csv
에서 할 수 합니다.COPY
그리고.SEARCH
(또는)FIND
무엇인가 상자에서 되지만, "DOS", "DOS"를 설치하는 은 어떨까요?cygwin
그리고 유닉스 명령 셸의 힘을 얻습니까?
이것은 제가 모든 CSV 파일을 R로 읽기 위해 개발한 코드입니다.각 csv 파일에 대해 개별적으로 데이터 프레임을 만들고 해당 데이터 프레임의 원래 이름(공백 및 .csv 제거)을 제목으로 지정합니다. 유용하게 사용하시기 바랍니다!
path <- "C:/Users/cfees/My Box Files/Fitness/"
files <- list.files(path=path, pattern="*.csv")
for(file in files)
{
perpos <- which(strsplit(file, "")[[1]]==".")
assign(
gsub(" ","",substr(file, 1, perpos-1)),
read.csv(paste(path,file,sep="")))
}
제가 보기에, 대부분의 다른 답변들은 다음과 같습니다.rio::import_list
간결한 한 줄기 선입니다.
library(rio)
my_data <- import_list(dir("path_to_directory", pattern = ".csv"), rbind = TRUE)
인수는 " 가인다전달니됩다로음으추는수다니▁are됩"로됩니다.rio::import
.rio
R이 읽을 수 있는 거의 모든 파일 형식을 처리할 수 있으며 사용합니다.data.table
의fread
가능하다면, 그것은 또한 빠를 것입니다.
용사를 합니다.plyr::ldply
다을활하속약도가면다니증가합 50%▁the를 활성화하면 가 약% 합니다..parallel
각각 약 30-40MB의 CSV 파일을 읽는 동안 옵션을 사용할 수 있습니다.예에는 텍스트 진행률 표시줄이 포함됩니다.
library(plyr)
library(data.table)
library(doSNOW)
csv.list <- list.files(path="t:/data", pattern=".csv$", full.names=TRUE)
cl <- makeCluster(4)
registerDoSNOW(cl)
pb <- txtProgressBar(max=length(csv.list), style=3)
pbu <- function(i) setTxtProgressBar(pb, i)
dt <- setDT(ldply(csv.list, fread, .parallel=TRUE, .paropts=list(.options.snow=list(progress=pbu))))
stopCluster(cl)
용사를 합니다.purrr
파일 ID를 열로 포함:
library(tidyverse)
p <- "my/directory"
files <- list.files(p, pattern="csv", full.names=TRUE) %>%
set_names()
merged <- files %>% map_dfr(read_csv, .id="filename")
없이.set_names()
,.id=
에서는 실제 파일 이름 대신 정수 표시기를 사용합니다.
전체 경로 없이 짧은 파일 이름만 원하는 경우:
merged <- merged %>% mutate(filename=basename(filename))
dnlbrk의 코멘트를 바탕으로 큰 파일의 경우 list2env보다 할당이 상당히 빠를 수 있습니다.
library(readr)
library(stringr)
List_of_file_paths <- list.files(path ="C:/Users/Anon/Documents/Folder_with_csv_files/", pattern = ".csv", all.files = TRUE, full.names = TRUE)
full.names 인수를 true로 설정하면 각 파일에 대한 전체 경로가 파일 목록의 별도 문자열로 표시됩니다. 예를 들어 List_of_file_paths[1]는 "C:/Users/Anon/Documents/Folder_with_csv_file/file1.csv"와 같습니다.
for(f in 1:length(List_of_filepaths)) {
file_name <- str_sub(string = List_of_filepaths[f], start = 46, end = -5)
file_df <- read_csv(List_of_filepaths[f])
assign( x = file_name, value = file_df, envir = .GlobalEnv)
}
read_csv 대신 data.table 패키지의 fread 또는 baseRread.csv를 사용할 수 있습니다.file_name 단계를 사용하면 각 데이터 프레임이 파일의 전체 경로를 그대로 유지하지 않도록 이름을 정리할 수 있습니다.글로벌 환경으로 전송하기 전에 루프를 확장하여 데이터 테이블에 추가 작업을 수행할 수 있습니다. 예를 들어 다음과 같습니다.
for(f in 1:length(List_of_filepaths)) {
file_name <- str_sub(string = List_of_filepaths[f], start = 46, end = -5)
file_df <- read_csv(List_of_filepaths[f])
file_df <- file_df[,1:3] #if you only need the first three columns
assign( x = file_name, value = file_df, envir = .GlobalEnv)
}
다음은 여러 파일을 읽고 하나의 데이터 프레임으로 결합하는 구체적인 예입니다.
path<- file.path("C:/folder/subfolder")
files <- list.files(path=path, pattern="/*.csv",full.names = T)
library(data.table)
data = do.call(rbind, lapply(files, function(x) read.csv(x, stringsAsFactors = FALSE)))
2 이후 에서는 Reader 2.0.0에 만 하면 여러 파일을 한 수 .file
논쟁.다음은 이를 보여주는 예입니다.readr::read_csv()
.
packageVersion("readr")
#> [1] '2.0.1'
library(readr)
library(fs)
# create files to read in
write_csv(read_csv("1, 2 \n 3, 4", col_names = c("x", "y")), file = "file1.csv")
write_csv(read_csv("5, 6 \n 7, 8", col_names = c("x", "y")), file = "file2.csv")
# get a list of files
files <- dir_ls(".", glob = "file*csv")
files
#> file1.csv file2.csv
# read them in at once
# record paths in a column called filename
read_csv(files, id = "filename")
#> # A tibble: 4 × 3
#> filename x y
#> <chr> <dbl> <dbl>
#> 1 file1.csv 1 2
#> 2 file1.csv 3 4
#> 3 file2.csv 5 6
#> 4 file2.csv 7 8
2021-09-16에 reprex 패키지에 의해 생성됨 (v2.0.1)
다음 코드는 컴퓨터에 많은 코어가 있는 한 빅데이터에 대해 가장 빠른 속도를 제공합니다.
if (!require("pacman")) install.packages("pacman")
pacman::p_load(doParallel, data.table, stringr)
# get the file name
dir() %>% str_subset("\\.csv$") -> fn
# use parallel setting
(cl <- detectCores() %>%
makeCluster()) %>%
registerDoParallel()
# read and bind all files together
system.time({
big_df <- foreach(
i = fn,
.packages = "data.table"
) %dopar%
{
fread(i, colClasses = "character")
} %>%
rbindlist(fill = TRUE)
})
# end of parallel work
stopImplicitCluster(cl)
2020/04/16 업데이트: 병렬 계산에 사용할 수 있는 새로운 패키지를 찾았을 때 다음 코드를 사용하여 대체 솔루션이 제공됩니다.
if (!require("pacman")) install.packages("pacman")
pacman::p_load(future.apply, data.table, stringr)
# get the file name
dir() %>% str_subset("\\.csv$") -> fn
plan(multiprocess)
future_lapply(fn,fread,colClasses = "character") %>%
rbindlist(fill = TRUE) -> res
# res is the merged data.table
나는 사용하는 접근 방식을 좋아합니다.list.files()
,lapply()
그리고.list2env()
(또는)fs::dir_ls()
,purrr::map()
그리고.list2env()
단순하고 유연해 보입니다.
또는 다음과 같은 작은 패키지 {tor}(to-R)를 사용해 볼 수 있습니다.기본적으로 작업 디렉토리에서 목록으로 파일을 가져옵니다.list_*()
글로벌 환경)으로 이동합니다.load_*()
변형).
예를 들어, 여기서는 다음을 사용하여 작업 디렉토리의 모든 .csv 파일을 목록으로 읽습니다.
library(tor)
dir()
#> [1] "_pkgdown.yml" "cran-comments.md" "csv1.csv"
#> [4] "csv2.csv" "datasets" "DESCRIPTION"
#> [7] "docs" "inst" "LICENSE.md"
#> [10] "man" "NAMESPACE" "NEWS.md"
#> [13] "R" "README.md" "README.Rmd"
#> [16] "tests" "tmp.R" "tor.Rproj"
list_csv()
#> $csv1
#> x
#> 1 1
#> 2 2
#>
#> $csv2
#> y
#> 1 a
#> 2 b
이제 다음을 통해 이러한 파일을 글로벌 환경에 로드합니다.
# The working directory contains .csv files
dir()
#> [1] "_pkgdown.yml" "cran-comments.md" "CRAN-RELEASE"
#> [4] "csv1.csv" "csv2.csv" "datasets"
#> [7] "DESCRIPTION" "docs" "inst"
#> [10] "LICENSE.md" "man" "NAMESPACE"
#> [13] "NEWS.md" "R" "README.md"
#> [16] "README.Rmd" "tests" "tmp.R"
#> [19] "tor.Rproj"
load_csv()
# Each file is now available as a dataframe in the global environment
csv1
#> x
#> 1 1
#> 2 2
csv2
#> y
#> 1 a
#> 2 b
파일을 할 해당 경로를 특파 일읽하경는해경파를로일당우와 시킬 수 .regexp
,ignore.case
그리고.invert
.
더욱 유연하게 사용할 수 있습니다.인수를 통해 판독기 기능을 제공할 수 있습니다..f
.
(path_csv <- tor_example("csv"))
#> [1] "C:/Users/LeporeM/Documents/R/R-3.5.2/library/tor/extdata/csv"
dir(path_csv)
#> [1] "file1.csv" "file2.csv"
list_any(path_csv, read.csv)
#> $file1
#> x
#> 1 1
#> 2 2
#>
#> $file2
#> y
#> 1 a
#> 2 b
다음을 통해 추가 인수 전달...또는 람다 함수 내부.
path_csv %>%
list_any(readr::read_csv, skip = 1)
#> Parsed with column specification:
#> cols(
#> `1` = col_double()
#> )
#> Parsed with column specification:
#> cols(
#> a = col_character()
#> )
#> $file1
#> # A tibble: 1 x 1
#> `1`
#> <dbl>
#> 1 2
#>
#> $file2
#> # A tibble: 1 x 1
#> a
#> <chr>
#> 1 b
path_csv %>%
list_any(~read.csv(., stringsAsFactors = FALSE)) %>%
map(as_tibble)
#> $file1
#> # A tibble: 2 x 1
#> x
#> <int>
#> 1 1
#> 2 2
#>
#> $file2
#> # A tibble: 2 x 1
#> y
#> <chr>
#> 1 a
#> 2 b
이 기능을 스택 오버플로 R 패키지에 추가하도록 요청했습니다.이 패키지는 매우 작은 버전의 패키지이므로(타사 패키지에 의존할 수 없음), 제가 생각해 낸 것은 다음과 같습니다.
#' Bulk import data files
#'
#' Read in each file at a path and then unnest them. Defaults to csv format.
#'
#' @param path a character vector of full path names
#' @param pattern an optional \link[=regex]{regular expression}. Only file names which match the regular expression will be returned.
#' @param reader a function that can read data from a file name.
#' @param ... optional arguments to pass to the reader function (eg \code{stringsAsFactors}).
#' @param reducer a function to unnest the individual data files. Use I to retain the nested structure.
#' @param recursive logical. Should the listing recurse into directories?
#'
#' @author Neal Fultz
#' @references \url{https://stackoverflow.com/questions/11433432/how-to-import-multiple-csv-files-at-once}
#'
#' @importFrom utils read.csv
#' @export
read.directory <- function(path='.', pattern=NULL, reader=read.csv, ...,
reducer=function(dfs) do.call(rbind.data.frame, dfs), recursive=FALSE) {
files <- list.files(path, pattern, full.names = TRUE, recursive = recursive)
reducer(lapply(files, reader, ...))
}
판독기와 감속기 기능을 매개변수화함으로써, 사람들은 원하는 경우 data.table 또는 dplyr을 사용하거나 더 작은 데이터 세트에 적합한 기본 R 함수를 사용할 수 있습니다.
이후 @leerssej의 "속도가 빠르고 간결한" 깔끔한 역 솔루션에 대한 업데이트.map_df
대체됨:
tbl <-
list.files(pattern = "*.csv") |>
map((\(fn) read_csv(fn)) |>
list_rbind()
언급URL : https://stackoverflow.com/questions/11433432/how-to-import-multiple-csv-files-at-once
'programing' 카테고리의 다른 글
IF 문의 값 목록과 비교하는 방법은 무엇입니까? (0) | 2023.06.18 |
---|---|
파이썬에서 openpyxl을 사용하여 Excel 스프레드시트에 행 삽입 (0) | 2023.06.18 |
cx_Oracle 및 예외 처리 - 모범 사례? (0) | 2023.06.18 |
Numpy: 각 행을 벡터 요소로 나눕니다. (0) | 2023.06.18 |
vuex를 사용하여 로컬 스토리지에 저장하는 다크 모드 (0) | 2023.06.18 |