Aynı anda birden fazla .csv dosyası nasıl alınır?


220

Her biri aynı sayıda değişken, ancak her biri farklı zamanlarda olan birden fazla data.csv dosyası içeren bir klasörümüz olduğunu varsayın. R'de hepsini tek tek içe aktarmak yerine hepsini aynı anda içe aktarmanın bir yolu var mı?

Benim sorunum yaklaşık 2000 veri dosyaları almak ve sadece kodu kullanarak tek tek almak zorunda olmasıdır:

read.delim(file="filename", header=TRUE, sep="\t")

çok verimli değil.

Yanıtlar:


259

Aşağıdakine benzer bir şey, her bir veri çerçevesinin tek bir listede ayrı bir öğe olarak sonuçlanması gerekir:

temp = list.files(pattern="*.csv")
myfiles = lapply(temp, read.delim)

Bu, bu CSV'lerin tek bir dizinde (geçerli çalışma dizininiz) olduğunu ve hepsinin küçük harf uzantısına sahip olduğunu varsayar .csv.

Daha sonra bu veri çerçevelerini tek bir veri çerçevesinde birleştirmek istiyorsanız do.call(rbind,...), dplyr::bind_rows()veya gibi şeyleri kullanarak diğer yanıtlardaki çözümlere bakın data.table::rbindlist().

Her veri çerçevesini ayrı bir nesnede gerçekten istiyorsanız, bu genellikle tavsiye edilemez olsa da, aşağıdakileri yapabilirsiniz assign:

temp = list.files(pattern="*.csv")
for (i in 1:length(temp)) assign(temp[i], read.csv(temp[i]))

Veya olmadan assignve (1) dosya adının nasıl temizlenebileceğini ve (2) nasıl kullanılacağını göstermek list2enviçin aşağıdakileri deneyebilirsiniz:

temp = list.files(pattern="*.csv")
list2env(
  lapply(setNames(temp, make.names(gsub("*.csv$", "", temp))), 
         read.csv), envir = .GlobalEnv)

Ama yine de, onları tek bir listede bırakmak genellikle daha iyidir.


Teşekkürler! bu çok iyi çalışıyor ... kolayca içe aktarabilmek için yeni içe aktardığım her dosyayı adlandırmayı nasıl başarabilirim?
Jojo Ono

bize bazı dosyalarınızın ilk birkaç satırını gösterebilirseniz bazı önerilerimiz olabilir - sorunuzu düzenleyin!
Spacedman

2
Yukarıdaki kod, onları tek nesne olarak içe aktarmak için mükemmel çalışır, ancak veri kümesinden bir sütun çağırmaya çalıştığımda, veri çerçevesi değil yalnızca tek bir nesne olduğu için tanımaz, yani yukarıdaki kodun sürümü: setwd ( 'C: / Users / new / Desktop / Dives / 0904_003') temp <-list.files (pattern = "*. Csv") ddives <- lapply (temp, read.csv) Artık her dosya ddives olarak adlandırılıyor [n ] ama onları tek nesneler yerine tüm veri çerçevelerini yapmak için bir döngü yazmaya nasıl devam edebilirim? Bunu bireysel olarak data.frame operatörünü kullanarak başarabilirim, ancak bunu nasıl döngü yapacağım konusunda emin değilim. @mrdwab
Jojo Ono

@JosephOnoufriou, güncellememe bakın. Ancak genel olarak, tüm veri çerçevelerinde benzer hesaplamalar yapacaksam listelerle çalışmayı daha kolay buluyorum.
A5C1D2H2I1M1N2O1R2T1

2
Bu cevabın güncellenmiş versiyonunu kullanarak bir fonksiyon yazmaya çalışan herkes için assign... Atanan değerlerin global ortamda kalmasını istiyorsanız, ayarladığınızdan emin olun inherits=T.
dnlbrky

127

Hızlı ve özlü bir tidyverseçözüm: ( Base R'lerin iki katından daha hızlı read.csv)

tbl <-
    list.files(pattern = "*.csv") %>% 
    map_df(~read_csv(.))

ve data.table 'lar fread()bu yükleme sürelerini tekrar yarıya indirebilir. ( Base R sürelerinin 1 / 4'ü için )

library(data.table)

tbl_fread <- 
    list.files(pattern = "*.csv") %>% 
    map_df(~fread(.))

stringsAsFactors = FALSEArgüman, dataframe faktörü serbest tutar (ve mermer çıkış noktaları olarak, varsayılan ayardır fread)

Yazım hatası arsız ise, tüm sütunları col_typesargümanla karakter olarak zorlayabilirsiniz .

tbl <-
    list.files(pattern = "*.csv") %>% 
    map_df(~read_csv(., col_types = cols(.default = "c")))

Sonunda bağlanacak dosya listenizi oluşturmak için alt dizinlere daldırmak istiyorsanız, yol adını eklediğinizden ve dosyaları listenizde tam adlarıyla kaydettiğinizden emin olun. Bu, ciltleme çalışmasının geçerli dizinin dışında devam etmesini sağlar. (Tam yol adlarının, 'sınırlar' dizini boyunca hareket etmesine izin vermek için pasaport gibi çalıştığını düşünmek.)

tbl <-
    list.files(path = "./subdirectory/",
               pattern = "*.csv", 
               full.names = T) %>% 
    map_df(~read_csv(., col_types = cols(.default = "c"))) 

Hadley'in burada açıkladığı gibi (yaklaşık yarım):

map_df(x, f)etkili bir şekilde aynı do.call("rbind", lapply(x, f))....

Bonus Özellik - aşağıdaki yorumlarda Niks özellik isteği başına kayıtlara dosya adları ekleme:
* filenameHer kayda orijinal ekleyin .

Kod açıklandı: tabloların ilk okunması sırasında her kayda dosya adını eklemek için bir işlev yapın. Ardından basit read_csv()işlev yerine bu işlevi kullanın .

read_plus <- function(flnm) {
    read_csv(flnm) %>% 
        mutate(filename = flnm)
}

tbl_with_sources <-
    list.files(pattern = "*.csv", 
               full.names = T) %>% 
    map_df(~read_plus(.))

(Yazım ve alt dizin işleme yaklaşımları, read_plus()işlevin içinde, yukarıda önerilen ikinci ve üçüncü varyantlarda gösterildiği gibi de ele alınabilir .)

### 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)")

Orta Kullanım Davası

Geçen Zaman Kutusunun Karşılaştırılması Tipik kullanım durumum

Daha Büyük Kullanım Durumu

Ekstra Büyük Yük için Geçen Sürenin Boxplot Karşılaştırması

Çeşitli Kullanım Durumları

Satırlar: dosya sayısı (1000, 100, 10)
Sütunlar: son veri çerçevesi boyutu (5MB, 50MB, 500MB)
(orijinal boyutunu görüntülemek için resme tıklayın) Dizin Boyutu Varyasyonlarının Boxplot Karşılaştırması

Temel R sonuçları, daha büyük ölçekli işleme görevleri gerçekleştirilirken gözlenen performans kazanımlarından ağır basmak için purrr ve dplyr C kütüphanelerini getirme yükünün daha küçük olduğu durumlarda daha iyidir.

kendi testlerinizi yapmak istiyorsanız bu bash betiğini yararlı bulabilirsiniz.

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 dosyanızın sırayla numaralandırılmış 100 kopyasını oluşturur (dosya adının ilk 8 karakterinden ve alt çizgiden sonra).

Atıflar ve Takdirler

Özel teşekkürler:

  • Tyler Rinker ve Akrun , mikrobenchmark gösterdikleri için.
  • Jake Kaupp beni map_df() buraya tanıttığı için .
  • Görselleştirmeleri iyileştirme ve küçük dosyada gözlemlenen performans terslemelerini tartışma / onaylama konusunda yararlı geri bildirim için David McLaughlin, küçük veri çerçevesi analiz sonuçları.
  • için varsayılan davranışı belirtmek amacıyla işaretleyin fread(). (Üzerinde çalışmam gerek data.table.)

1
çözüm benim için çalışıyor. Bu dosyada onları ayırt etmek için bu dosya adını saklamak istiyorum .. Bu mümkün mü?
Niks

1
@Niks - Kesinlikle! Sadece dosyaları okumakla kalmayan, aynı zamanda okunan her kayda hemen bir dosya adı ekleyen küçük bir işlevle yazıp değiştirin. Böylece gibi readAddFilename <- function(flnm) { read_csv(flnm) %>% mutate(filename = flnm) }Sonra sadece için o damla map_dfyerine basit sadece okumak read_csv()artık bulunmadığını söyledi. Hala sorularınız varsa veya bunun yararlı olacağını düşünüyorsanız, işlevi ve boruya nasıl sığacağını göstermek için yukarıdaki girişi güncelleyebilirim.
leerssej

Uygulamadaki sorun, bundan read_csvdaha yavaş olmasıdır fread. Bir şeyin daha hızlı olduğunu söyleyecek olursanız, bir karşılaştırma ölçütü eklerim. Bir fikir 30 1GB dosya oluşturmak ve bunları okumaktır, bu performansın önemli olduğu bir durumdur.
marbel

@marbel: Öneri için teşekkürler! 530 MB ve (en fazla 100 dosyalarla) daha küçük dizinleri ben arasında performans açısından% 25 iyileşme bulma am data.table 'ler fread()ve dplyr ' ler read_csv(): 14.2 19.9 vs sn. TBH, sadece R tabanını dplyr ile karşılaştırıyordum ve kıyaslamadan read_csv()yaklaşık 2-4x daha hızlı olduğu için read.csv()kıyaslama gerekli görünmüyordu. Bununla birlikte fread(), daha eksiksiz kıyaslama sonuçlarını kontrol etmek için bir koşuşturma ve duraklama vermek ilginçti . Tekrar teşekkürler!
leerssej

1
Başka bir harika nokta. Ben data.table faaliyetlerini yerinde veri (bu sonraki ve sonraki tüm veri için performansı etkiler) performansı mutasyona karşı korumak konusunda biraz dikkatli olduğumu yazarken düşünüyorum. Bu durumda elbette mantıklı değil. Teşekkür ederim. :-D Fonksiyonlar olmadan ve daha büyük bir makine ile daha büyük veri kümeleriyle sayıları yakında tekrar çalıştırmak için sabırsızlanıyoruz.
leerssej

105

R tabanını kullanarak .csv dosyalarını bir data.frame'e dönüştürmek için bazı seçenekler ve R'deki dosyaları okumak için mevcut bazı paketler.

Bu, aşağıdaki seçeneklerden daha yavaştı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)))

Düzenleme: - data.tableve kullanarak birkaç ekstra seçenekreadr

Paketin fread()bir fonksiyonu olan bir versiyon data.table. Bu, R'deki en hızlı seçenektir .

library(data.table)
DT = do.call(rbind, lapply(files, fread))
# The same using `rbindlist`
DT = rbindlist(lapply(files, fread))

Kullanılması readr CSV dosyalarını okumak için başka pakettir. freadR tabanından daha yavaş , daha hızlıdır ancak farklı işlevlere sahiptir.

library(readr)
library(dplyr)
tbl = lapply(files, read_csv) %>% bind_rows()

2
bu nasıl Reduce (rbind, lapply (...)) ile karşılaştırıldığında Sadece R öğrenmek ama benim tahminim daha az performans
aaron

4
data.tablePerformansı artıracak bir sürüm ekledim .
marbel

Sadece belirli dosyaları okumak mümkün mü? eski adında 'hava durumu' içeren dosyalar?
Sahipsiz

1
burada buldum: stackoverflow.com/questions/10353540/… teşekkürler.
Sahipsiz

1
+1, tek bir veri çerçevesi üretmek gibi görünüyor - tüm CSV dosyalarının SQL UNION'ı - çalışmak en kolayı. OP, 1 veri çerçevesi mi yoksa birçok veri çerçevesi mi istediklerini belirtmediğinden, 1 veri çerçevesinin en iyi olduğunu varsaydım, bu yüzden kabul edilen cevabın "BİRLİĞİ" hiçbirini yapmadığını şaşırdım. Ben tutarlıdır bu cevap, gibi bu açıklamado.call
The Red Pea

24

lapplyR'de veya başka bir döngü yapısını kullanmanın yanı sıra , CSV dosyalarınızı tek bir dosyada birleştirebilirsiniz.

Unix'te, dosyaların üstbilgisi yoksa, o kadar kolay:

cat *.csv > all.csv

veya üstbilgiler varsa ve üstbilgilerle ve yalnızca üstbilgilerle eşleşen bir dize bulabilirseniz (örneğin, üstbilgi satırlarının tümü "Yaş" ile başlıyorsa):

cat *.csv | grep -v ^Age > all.csv

Windows'da bunu DOS komut kutusundan COPYve SEARCH(veya bir FINDşeyden) yapabileceğinizi düşünüyorum , ancak neden cygwinUnix komut kabuğunun gücünü kurup almayasınız?


hatta kurulumla uğraşan Git Bash ile Gitmi?
leerssej

Deneyimlerime göre, dosyalarınız oldukça büyük olmaya başlarsa, bu en hızlı çözüm değildir.
Amir

21

Bu, tüm csv dosyalarını R'ye okumak için geliştirilen kod. Her bir csv dosyası için ayrı ayrı bir veri çerçevesi oluşturacak ve dosyanın orijinal adını (boşluklar ve .csv kaldırma) veri çerçevesi başlatacak.

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="")))
}

9

@ A5C1D2H2I1M1N2O1R2T1, @leerssej ve @marbel tarafından verilen en önemli üç yanıtın hepsi aynıdır: her dosyaya fread uygulayın, ardından ortaya çıkan verileri rbind / rbindlistlayın. Genellikle rbindlist(lapply(list.files("*.csv"),fread))formu kullanırım .

Bu, diğer R-dahili alternatiflerden daha iyidir ve az sayıda büyük csvs için iyidir, ancak hız önemli olduğunda çok sayıda küçük csvs için en iyisi değildir. Bu durumda, cat@Spacedman 4. sıradaki cevapta önerdiği gibi, ilk kullanım çok daha hızlı olabilir . Bunu R içinden nasıl yapacağınıza dair biraz ayrıntı ekleyeceğim:

x = fread(cmd='cat *.csv', header=F)

Ancak, her csv'nin bir başlığı varsa ne olur?

x = fread(cmd="awk 'NR==1||FNR!=1' *.csv", header=T)

Ya *.csvkabuk kabuğunun başarısız olduğu çok fazla dosyanız varsa ?

x = fread(cmd='find . -name "*.csv" | xargs cat', header=F)

Ve tüm dosyaların bir başlığı varsa ve çok fazla dosya varsa ne olur?

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)
names(x) = names(header)

Peki ya sonuçtaki birleştirilmiş csv sistem belleği için çok büyükse?

system('find . -name "*.csv" | xargs cat > combined.csv')
x = fread('combined.csv', header=F)

Üstbilgilerle mi?

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)

Son olarak, bir dizindeki tüm .csv dosyasını değil, belirli bir dosya kümesini istemiyorsanız ne olur? (Ayrıca, hepsinin başlığı vardır.) (Bu benim kullanım durumum.)

fread(text=paste0(system("xargs cat|awk 'NR==1||$1!=\"<column one name>\"'",input=paths,intern=T),collapse="\n"),header=T,sep="\t")

ve bu düz fread xargs cat ile aynı hızda :)

Not: data.table öncesi v1.11.6 (19 Eylül 2018) için, ihmal cmd=dan fread(cmd=.

Zeyilname: Örneğin seri lapply yerine paralel kütüphanenin rbindlist(lapply(list.files("*.csv"),fread))mclapply kullanılması rbindlist lapply fread'den çok daha hızlıdır.

Tek bir veri halinde 121401 csvs okuma zamanı. Tablo. Her csv'de 3 sütun, bir başlık satırı ve ortalama olarak 4.510 satır bulunur. Makine 96 çekirdekli bir GCP VM'dir:

rbindlist lapply fread   234.172s 247.513s 256.349s
rbindlist mclapply fread  15.223s   9.558s   9.292s
fread xargs cat            4.761s   4.259s   5.095s

Özetle, hızla ilgileniyorsanız ve birçok dosyaya ve çok sayıda çekirdeğe sahipseniz, fread xargs cat ilk 3 yanıttaki en hızlı çözümden yaklaşık 50 kat daha hızlıdır.


6

Benim görüşüme göre, diğer cevapların çoğu eskimiş rio::import_list, tek bir özlü:

library(rio)
my_data <- import_list(dir("path_to_directory", pattern = ".csv", rbind = TRUE))

Ek argümanlar iletilir rio::import. riookuyabilir hemen her dosya formatı R ile anlaşma ve kullandığı olabilir data.table's freadmümkünse çok hızlı olmalı, böylece.


5

Kullanarak plyr::ldplyetkinleştirerek% 50 hız artışı kabaca orada .parallelkabaca 30-40 MB her 400 csv dosyalarını okurken seçeneği. Örnek bir metin ilerleme çubuğu içerir.

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)

Güzel cevap! Ek argümanları freadveya öğesine nasıl iletirsiniz user-defined functions? Teşekkürler!
Tung

1
@Tung Looking, aktarılan diğer argümanları ?ldplygösterir . Ya birini kullanmak ya da işe ....funfread, skip = 100function(x) fread(x, skip = 100)
yarar

kullanma function(x) fread(x, skip = 100)benim için işe yaramadı ama çıplak işlev adından sonra ek argümanlar sağlamak hile yaptı. Tekrar teşekkürler!
Tung

3

Dnlbrk'un yorumuna dayanarak, atama büyük dosyalar için list2env'den çok daha hızlı olabilir.

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 bağımsız değişkenini true olarak ayarladığınızda, her bir dosyanın tam yolunu dosya listenizde ayrı bir karakter dizesi olarak alırsınız; ör. List_of_file_paths [1] "C: / Users / Anon / Documents / Folder_with_csv_files / 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)
}

Data.table paketinin fread veya base R read.csv yerine read_csv kullanabilirsiniz. Dosya_adı adımı, her veri çerçevesinin ad olarak dosyanın tam yolunda kalmaması için adı düzenlemenize olanak tanır. Döngünüzü, küresel ortama aktarmadan önce veri tablosuna başka şeyler yapmak için genişletebilirsiniz, örneğin:

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)
}

3

Birden fazla dosyayı okumak ve bunları 1 veri çerçevesinde birleştirmek için benim özel örneğim:

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)))

1
Sen kullanabilirsiniz rbindlist()dendata.table
jogo

3

Aşağıdaki kodlar, bilgisayarınızda birçok çekirdek olduğu sürece büyük veriler için en yüksek hızı vermelidir:

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 yılında güncellendi: Paralel hesaplama için yeni bir paket bulduğumda, aşağıdaki kodlar kullanılarak alternatif bir çözüm sağlandı.

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

1

Ben yaklaşım kullanarak gibi list.files(), lapply()ve list2env()(veya fs::dir_ls(), purrr::map()ve list2env()). Bu basit ve esnek görünüyor.

Alternatif olarak, küçük paketi { tor } ( to-R ) deneyebilirsiniz : Varsayılan olarak, dosyaları çalışma dizininden bir listeye ( list_*()varyantlar) veya genel ortama ( load_*()varyantlar) alır.

Örneğin, burada çalışma dizinimdeki tüm .csv dosyalarını kullanarak bir listeye okudum tor::list_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

Ve şimdi bu dosyaları global ortamıma aşağıdakilerle yüklüyorum tor::load_csv():

# 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

Belirli dosyalarını okumak gerekiyorsa, sen onların dosya yolunu eşleşebilir regexp, ignore.caseve invert.


Daha fazla esneklik için kullanın list_any(). Bağımsız değişken aracılığıyla okuyucu işlevini sağlamanızı sağlar .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

... veya lambda fonksiyonunun içinde ek argümanlar iletin.

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

1

Bu işlevi stackoverflow R paketine eklemem istendi. Bunun küçük bir paket olduğu (ve üçüncü taraf paketlerine bağlı olamayacağı) göz önüne alındığında, işte ben geldi:

#' 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{/programming/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, ...))
}

Okuyucu ve redüktör fonksiyonunu parametreleştirerek, insanlar bunu seçerse data.table veya dplyr kullanabilir veya sadece daha küçük veri kümeleri için iyi olan temel R işlevlerini kullanabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.