एक साथ कई .csv फ़ाइलों को आयात करने के लिए कैसे?


219

मान लें कि हमारे पास एक फ़ोल्डर है जिसमें कई data.csv फाइलें हैं, जिनमें से प्रत्येक में समान संख्या में चर हैं लेकिन प्रत्येक अलग-अलग समय से हैं। क्या आर में एक तरीका है कि उन सभी को एक साथ आयात करने के बजाय उन सभी को व्यक्तिगत रूप से आयात किया जाए?

मेरी समस्या यह है कि मेरे पास आयात करने के लिए लगभग 2000 डेटा फाइलें हैं और कोड का उपयोग करके उन्हें व्यक्तिगत रूप से आयात करना है:

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

बहुत कुशल नहीं है।

जवाबों:


259

निम्नलिखित की तरह कुछ परिणाम प्रत्येक डेटा फ्रेम में एक ही सूची में एक अलग तत्व के रूप में होना चाहिए:

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, और (1) प्रदर्शित करने के लिए कि फ़ाइल का नाम कैसे साफ किया जा सकता है और (2) कैसे उपयोग करने के लिए दिखाया गया है list2env, आप निम्नलिखित की कोशिश कर सकते हैं:

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

लेकिन फिर, उन्हें अक्सर एक ही सूची में छोड़ना बेहतर होता है।


धन्यवाद! यह बहुत अच्छी तरह से काम करता है ... मैं अपने द्वारा आयात की गई प्रत्येक फ़ाइल का नामकरण कैसे करूंगा ताकि मैं उन्हें आसानी से कॉल कर सकूं?
जोजो ओनो

यदि आप हमें अपनी कुछ फ़ाइलों की पहली कुछ पंक्तियाँ दिखा सकते हैं तो हमारे पास कुछ सुझाव हो सकते हैं - उसके लिए अपने प्रश्न को संपादित करें!
१३:१३ बजे स्पेल्डमैन

2
उपरोक्त कोड उन्हें एकल ऑब्जेक्ट के रूप में आयात करने के लिए पूरी तरह से काम करता है, लेकिन जब मैं डेटा सेट से एक कॉलम को कॉल करने की कोशिश करता हूं, तो इसे पहचानता नहीं है क्योंकि यह केवल एक ही ऑब्जेक्ट है न कि डेटा फ़्रेम यानी उपरोक्त कोड का मेरा संस्करण है: सेटवार्ड ( 'C: / Users / new / Desktop / Dives / 0904_003') temp <-list.files (pattern = "*। Csv") ddives <- lapply (temp, read.csv) अब प्रत्येक फ़ाइल को ddives [n] कहा जाता है। ] लेकिन मैं उन सभी डेटा फ़्रेमों को एकल ऑब्जेक्ट के बजाय बनाने के लिए एक लूप लिखने के बारे में कैसे जाऊंगा? मैं डेटा.फ्रेम ऑपरेटर का उपयोग करके इसे व्यक्तिगत रूप से प्राप्त कर सकता हूं लेकिन यह सुनिश्चित करने के लिए अनिश्चित हूं कि इसे कैसे लूप किया जाए। @ मर्दवाब
जोजो ओनो

@JosephOnoufriou, मेरा अपडेट देखें। लेकिन आम तौर पर, मुझे सूचियों के साथ काम करना आसान लगता है अगर मैं सभी डेटा फ़्रेमों पर समान गणना करने जा रहा हूं।
A5C1D2H2I1M1N2O1R2T1

2
इस उत्तर के अपडेट किए गए संस्करण का उपयोग करने के लिए फ़ंक्शन लिखने की कोशिश करने वाले किसी भी व्यक्ति के लिए assign... यदि आप चाहते हैं कि असाइन किए गए मान वैश्विक वातावरण में रहें, तो सुनिश्चित करें कि आपने सेट किया है inherits=T
dnlbrky

127

एक त्वरित और संक्षिप्त tidyverseसमाधान: ( बेस आर के दोगुने से अधिक तेज read.csv)

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

और data.table का fread()लोड समय फिर से आधा हो सकता है। (1/4 बेस आर बार के लिए)

library(data.table)

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

stringsAsFactors = FALSEतर्क dataframe कारक मुक्त रहता है, (और marbel अंक बाहर के रूप में, के लिए डिफ़ॉल्ट सेटिंग है 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"))) 

जैसा कि हेडली ने यहाँ वर्णन किया है (लगभग आधा नीचे):

map_df(x, f)प्रभावी रूप से के रूप में ही है do.call("rbind", lapply(x, f))....

बोनस फ़ीचर - नीचे दिए गए टिप्पणियों में रिकॉर्ड में फ़ीचर अनुरोध में फ़ाइल नाम जोड़ना:
* 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)
(मूल आकार देखने के लिए चित्र पर क्लिक करें) Boxplot निर्देशिका आकार भिन्नता की तुलना

आधार आर परिणाम सबसे छोटे उपयोग के मामलों के लिए बेहतर होते हैं जहां बड़े पैमाने पर प्रसंस्करण कार्यों का प्रदर्शन करते समय प्रदर्शन लाभ प्राप्त करने के लिए पूर्र और सी के पुस्तकालयों को लाने के ओवरहेड होते हैं।

यदि आप अपने स्वयं के परीक्षण चलाना चाहते हैं तो आपको यह बैश स्क्रिप्ट मददगार लग सकती है।

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 क्रमिक रूप से गिने आपकी फ़ाइल की 100 प्रतियां बनाएगा (फ़ाइल नाम और अंडरस्कोर के प्रारंभिक 8 वर्णों के बाद)।

गुण और प्रशंसा

विशेष धन्यवाद के साथ:

  • माइक्रोएन्चमार्क के प्रदर्शन के लिए टायलर रिंकर और अक्रुन।
  • मेरे लिए शुरू करने के लिए जेक KAUPP map_df() यहाँ
  • डेविड मैकलॉघलिन ने विज़ुअलाइज़ेशन में सुधार करने और छोटी फ़ाइल, छोटे डेटाफ़्रेम विश्लेषण परिणामों में देखे गए प्रदर्शन व्युत्क्रमों पर चर्चा / पुष्टि करने में सहायक प्रतिक्रिया के लिए।
  • के लिए डिफ़ॉल्ट व्यवहार को इंगित करने के लिए marbel fread()। (मुझे अध्ययन करने की आवश्यकता है data.table।)

1
आप समाधान मेरे लिए काम करता है। इसमें मैं उस फ़ाइल का नाम उन्हें अलग करने के लिए संग्रहीत करना चाहता हूं .. क्या यह संभव है?
निक्स

1
@ निक्स - निश्चित रूप से! बस एक छोटे से फ़ंक्शन में लिखें और स्वैप करें जो न केवल फ़ाइलों को पढ़ता है, बल्कि प्रत्येक रिकॉर्ड पढ़ने के लिए तुरंत एक फ़ाइलनाम जोड़ता है। जैसे कि readAddFilename <- function(flnm) { read_csv(flnm) %>% mutate(filename = flnm) }तब बस इतना है कि map_dfसरल पढ़ने के बजाय केवल read_csv()अब वहाँ है। मैं फ़ंक्शन को दिखाने के लिए ऊपर प्रविष्टि को अपडेट कर सकता हूं और यह पाइप में कैसे फिट होगा यदि आपके पास अभी भी प्रश्न हैं या आपको लगता है कि मददगार होगा।
लेरसेज

व्यवहार में समस्या यह है कि read_csvबहुत अधिक धीमी है fread। यदि आप कुछ कहना चाहते हैं तो मैं एक बेंचमार्क शामिल करूंगा। एक विचार 30 1GB फाइलें बना रहा है और उन्हें पढ़ रहा है, यह एक ऐसा मामला होगा जहां प्रदर्शन मायने रखता है।
मारबेल

@marbel: सुझाव के लिए धन्यवाद! पर 530 MB और छोटे निर्देशिका (अधिकतम 100 फाइलों के साथ) मैं के बीच प्रदर्शन में एक 25% सुधार लग रहा है data.table की fread()और dplyr की read_csv(): 14.2 बनाम 19.9 सेकेंड। टीबीएच, मैं केवल बेस आर की तुलना dplyr से कर रहा था और जैसा read_csv()कि लगभग 2-4x तेज है read.csv(), बेंचमार्किंग आवश्यक नहीं लगता। हालांकि यह अधिक दिलचस्प है कि fread()अधिक पूर्ण बेंचमार्क परिणामों की जांच करने के लिए एक चक्कर और ठहराव दिया जाए। एक बार फिर धन्यवाद!
लीरसेज

1
एक और बेहतरीन बात। मुझे लगता है कि जब मैंने लिखा था कि मैं डेटा को जगह में रखने से डेटा को संरक्षित करने में थोड़ी सावधानी बरत रहा था (जो कि अगले और सभी बाद के रन के प्रदर्शन को प्रभावित करता है)। इस उदाहरण में इसका कोई मतलब नहीं है। धन्यवाद। :-D फंक्शंस के बिना और बड़ी डेटासेट वाली बड़ी मशीन के साथ जल्द ही फिर से नंबर चलाने के लिए उत्सुक हैं।
लीरसेज

104

यहां कुछ डेटा को .csv फ़ाइलों को एक डेटा में परिवर्तित करने के लिए कुछ विकल्प दिए गए हैं। R बेस का उपयोग करके और 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

एक fread()संस्करण, जो data.tableपैकेज का एक फ़ंक्शन है । आर में यह अब तक का सबसे तेज विकल्प है

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

रीड का उपयोग करना , जो सीएसवी फ़ाइलों को पढ़ने के लिए एक और पैकेज है। यह freadबेस आर की तुलना में तेज़ है , लेकिन अलग-अलग कार्यात्मकता है।

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

2
यह कैसे कम करता है बनाम (rbind, lapply (...))? सिर्फ R सीखना लेकिन मेरा अनुमान कम प्रदर्शन करने वाला है
aaron

4
मैंने एक data.tableसंस्करण जोड़ा है , जिससे प्रदर्शन में सुधार होना चाहिए।
मारबेल

क्या केवल विशिष्ट फ़ाइलों को पढ़ना संभव है? पूर्व फाइलें जिसमें नाम में 'मौसम' होता है?
Derelict

1
यह यहाँ पाया गया: stackoverflow.com/questions/10353540/… धन्यवाद।
Derelict

1
+1 ऐसा लगता है जैसे एकल डेटा फ़्रेम - सभी CSV फ़ाइलों का SQL UNION - के साथ काम करना सबसे आसान है। चूंकि ओपी ने निर्दिष्ट नहीं किया कि वे 1 डेटा फ़्रेम या कई डेटा फ़्रेम चाहते हैं, इसलिए मैंने माना कि 1 डेटा फ़्रेम सबसे अच्छा है, इसलिए मुझे आश्चर्य है कि स्वीकृत उत्तर "यूनिअन" में से कोई भी नहीं करता है। मुझे यह उत्तर पसंद है, जो इस स्पष्टीकरण केdo.call
द रेड मटर

24

lapplyआर में उपयोग या कुछ अन्य लूपिंग निर्माण के साथ-साथ आप अपनी CSV फ़ाइलों को एक फ़ाइल में मर्ज कर सकते हैं।

यूनिक्स में, यदि फ़ाइलों में हेडर नहीं था, तो यह उतना आसान है:

cat *.csv > all.csv

या यदि हेडर हैं, और आप एक स्ट्रिंग पा सकते हैं जो हेडर और केवल हेडर से मेल खाता है (अर्थात मान लें कि हेडर लाइनें "एज" से शुरू होती हैं), तो आप करेंगे:

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

मुझे लगता है कि विंडोज में आप डॉस कमांड बॉक्स से ऐसा कर सकते हैं COPYऔर SEARCH(या FINDकुछ) कर सकते हैं , लेकिन क्यों स्थापित न करें cygwinऔर यूनिक्स कमांड शेल की शक्ति प्राप्त करें?


या यहां तक कि गिट बैश के साथ जाएं जो Gitस्थापित के साथ टकराता है ?
लेरसेज

मेरे अनुभव में, यह सबसे तेज़ समाधान नहीं है यदि आपकी फाइलें बड़ी होने लगी हैं।
आमिर

20

यह वह कोड है जिसे मैंने आर में सभी सीएसवी फ़ाइलों को पढ़ने के लिए विकसित किया है। यह प्रत्येक सीएसवी फ़ाइल के लिए व्यक्तिगत रूप से एक डेटाफ्रेम बनाएगा और शीर्षक देगा कि डेटाफ्रेम फ़ाइल के मूल नाम (रिक्त स्थान और .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="")))
}

8

@ A5C1D2H2I1M1N2O1R2T1, @leerssej, और @marbel द्वारा शीर्ष तीन उत्तर दिए गए हैं और सभी अनिवार्य रूप से समान हैं: प्रत्येक फ़ाइल पर फ़्रेड लागू करें, फिर परिणामी data.tables को rbind / rindindlist करें। मैं आमतौर पर उपयोग करता हूंrbindlist(lapply(list.files("*.csv"),fread)) फॉर्म का ।

यह अन्य आर-आंतरिक विकल्पों की तुलना में बेहतर है, और बड़ी संख्या में बड़ी सीएसवी के लिए ठीक है, लेकिन गति के मामले में बड़ी संख्या में छोटे सीएसवी के लिए सबसे अच्छा नहीं है। उस मामले में, यह पहली बार उपयोग करने के लिए बहुत तेज़ हो सकता है cat, जैसा कि @Spacedman 4-रैंक वाले उत्तर में बताता है। मैं R के भीतर से यह करने के लिए कुछ विवरण जोड़ूंगा:

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

हालांकि, क्या होगा अगर प्रत्येक सीएसवी में हेडर है?

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

और क्या होगा अगर परिणामस्वरूप कॉनसेटेड सीएसवी सिस्टम मेमोरी के लिए बहुत बड़ा है?

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 बिल्ली :)

नोट: data.table पूर्व v1.11.6 (19 सितं, 2018) के लिए, छोड़ cmd=से fread(cmd=

परिशिष्ट: धारावाहिक के स्थान पर समान रूप से समानांतर लाइब्रेरी के mappapply का उपयोग करना, उदाहरण के लिए, rbindlist(lapply(list.files("*.csv"),fread))rbindlist lapply fread की तुलना में बहुत तेज़ है।

एक एकल डेटा में 121401 सीएसवी पढ़ने का समय। प्रत्येक सीएसवी में 3 कॉलम, एक हेडर पंक्ति और, औसतन 4.510 पंक्तियाँ होती हैं। मशीन 96 कोर वाला एक GCP VM है:

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

योग करने के लिए, यदि आप गति में रुचि रखते हैं, और कई फाइलें और कई कोर हैं, तो शीर्ष 3 उत्तरों में सबसे तेज़ समाधान की तुलना में फ़्रेड जार्ज कैट लगभग 50x तेज़ है।


6

मेरे विचार में, अधिकांश अन्य उत्तरों को मान लिया गया है rio::import_list, जो एक प्रकार का वन-लाइनर है।

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

किसी भी अतिरिक्त तर्क को पारित किया जाता है rio::importrioलगभग किसी भी फ़ाइल स्वरूप आर के साथ सौदा पढ़ सकते हैं कर सकते हैं और इसे इस्तेमाल करता है data.table's fread, जहां संभव तो यह तेजी से भी होना चाहिए।


5

लगभग 30-40 एमबी प्रत्येक में 400 सीएसवी फाइलें पढ़ते हुए विकल्प को plyr::ldplyसक्षम करने से लगभग 50% की गति वृद्धि का उपयोग करना है .parallel। उदाहरण में एक पाठ प्रगति पट्टी शामिल है।

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)

अच्छा उत्तर! आप अतिरिक्त तर्क कैसे पास करते हैं freadया user-defined functions? धन्यवाद!
तुंग

1
@ तुंग को देखते हुए अन्य तर्कों को ?ldplyदिखाया ...गया .funfread, skip = 100या तो उपयोग करना या function(x) fread(x, skip = 100)काम करना होगा
manotheshark

का उपयोग करते हुए function(x) fread(x, skip = 100)मेरे लिए काम नहीं किया था, लेकिन अतिरिक्त args उपलब्ध कराने के नंगे समारोह नाम के बाद चाल किया था। एक बार फिर धन्यवाद!
तुंग

3

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)

पूर्ण.नाम के तर्क को सही पर सेट करने से, आपको अपनी फ़ाइल की सूची में एक अलग वर्ण स्ट्रिंग के रूप में प्रत्येक फ़ाइल का पूरा रास्ता मिल जाएगा, उदाहरण के लिए, List_of_file_paths [1] कुछ इस तरह होगा "C: / Users / aon / 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)
}

आप डेटा का उपयोग कर सकते हैं। पैकेज के फ़्रेड या बेस R read.csv के बजाय read_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])  
  file_df <- file_df[,1:3] #if you only need the first three columns
  assign( x = file_name, value = file_df, envir = .GlobalEnv)
}

3

यह कई फ़ाइलों को पढ़ने और उन्हें 1 डेटा फ़्रेम में संयोजित करने के लिए मेरा विशिष्ट उदाहरण है:

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
आप rbindlist()सेdata.table
जोगो

3

निम्नलिखित कोड आपको बड़े डेटा के लिए सबसे तेज़ गति प्रदान करना चाहिए जब तक आपके कंप्यूटर पर कई कोर हैं:

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

1

मुझे उपयोग करने का तरीका पसंद है list.files(), lapply()और list2env()(या fs::dir_ls(), purrr::map()और list2env())। यह सरल और लचीला लगता है।

वैकल्पिक रूप से, आप छोटे पैकेज { tor } ( टू-आर ) की : डिफ़ॉल्ट रूप से यह कार्यशील निर्देशिका से फाइलों को एक सूची ( list_*()वेरिएंट) में या वैश्विक वातावरण में आयात करता है (load_*() वेरिएंट) में ।

उदाहरण के लिए, यहां मैंने अपनी वर्किंग डायरेक्टरी से सभी .csv फ़ाइलों को एक सूची में पढ़कर उपयोग किया है 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

और अब मैं उन फाइलों को अपने वैश्विक परिवेश में लोड करता हूं 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

क्या आपको विशिष्ट फ़ाइलों को पढ़ने की आवश्यकता है, आप उनके फ़ाइल-पथ के साथ मेल कर सकते हैं regexp,ignore.case और invert


और भी अधिक लचीलापन उपयोग के लिए list_any()। यह आपको तर्क के माध्यम से पाठक फ़ंक्शन की आपूर्ति करने की अनुमति देता है.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

1

यह अनुरोध किया गया था कि मैं स्टैकओवरफ्लो आर पैकेज में इस कार्यक्षमता को जोड़ दूं। यह देखते हुए कि यह एक छोटे पैकेज है (और तीसरे पक्ष के पैकेज पर निर्भर नहीं हो सकता है), यहाँ है कि मैं क्या लेकर आया हूँ:

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

रीडर और रिड्यूसर फ़ंक्शन को पैरामीटर द्वारा, लोग डेटाटैब या डंपलर का उपयोग कर सकते हैं यदि वे ऐसा चुनते हैं, या बस आधार आर फ़ंक्शन का उपयोग करते हैं जो छोटे डेटा सेट के लिए ठीक हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.