R'ye okumak için büyük (3,5 GB) bir csv dosyasını kırpma


87

Bu yüzden, çok fazla ayrıntıya ve eksik satırlara sahip bir veri dosyası (noktalı virgülle ayrılmış) var (Access ve SQL boğulacak). 40 yıl boyunca segmentlere, alt segmentlere ve alt segmentlere (toplam ~ 200 faktör için) ayrılmış ilçe düzeyinde veri seti. Kısacası, çok büyük ve basitçe okumaya çalışırsam hafızaya sığmayacak.

Öyleyse sorum şu, tüm ilçeleri, ancak yalnızca tek bir yıl (ve sadece en yüksek segment seviyesi ... sonunda yaklaşık 100.000 satıra yol açan) istediğim için, bunu elde etmenin en iyi yolu bu toplama R'ye mi?

Şu anda Python ile ilgisiz yılları kesmeye çalışıyorum, bir seferde bir satır okuyup çalıştırarak dosya boyutu sınırını aşmaya çalışıyorum, ancak yalnızca R'ye yönelik bir çözümü tercih ederim (CRAN paketleri TAMAM). R'de her seferinde bir parçayı dosyalarda okumanın benzer bir yolu var mı?

Herhangi bir fikir çok takdir edilecektir.

Güncelleme:

  • Kısıtlamalar
    • Makinemi kullanmam gerekiyor , bu nedenle EC2 bulut sunucusu yok
    • Mümkün olduğunca yalnızca R olarak. Makinem patlamazsa, bu durumda hız ve kaynaklar sorun değildir ...
    • Aşağıda görebileceğiniz gibi, veriler daha sonra üzerinde çalışmam gereken karma türleri içeriyor
  • Veri
    • Veriler, yaklaşık 8,5 milyon satır ve 17 sütunla 3,5 GB'tır
    • Birkaç bin satır (~ 2k) hatalı biçimlendirilmiş ve 17 yerine yalnızca bir sütun
      • Bunlar tamamen önemsizdir ve düşebilir
    • Bu dosyadan yalnızca ~ 100.000 satıra ihtiyacım var (Aşağıya bakın)

Veri örneği:

County; State; Year; Quarter; Segment; Sub-Segment; Sub-Sub-Segment; GDP; ...
Ada County;NC;2009;4;FIRE;Financial;Banks;80.1; ...
Ada County;NC;2010;1;FIRE;Financial;Banks;82.5; ...
NC  [Malformed row]
[8.5 Mill rows]

Verilerin R'ye sığabilmesi için bazı sütunları ayırmak ve mevcut 40 yıldan ikisini (1980-2020 arası 2009-2010) seçmek istiyorum:

County; State; Year; Quarter; Segment; GDP; ...
Ada County;NC;2009;4;FIRE;80.1; ...
Ada County;NC;2010;1;FIRE;82.5; ...
[~200,000 rows]

Sonuçlar:

Yapılan tüm önerileri düzelttikten sonra, JD ve Marek'in önerdiği readLines'ın en iyi sonucu vereceğine karar verdim. Marek'e bir örnek uygulama verdiği için çeki verdim.

Burada son cevabım için Marek uygulamasının biraz uyarlanmış bir versiyonunu yeniden ürettim, strsplit ve cat kullanarak sadece istediğim sütunları tutuyorum.

Bunun Python'dan ÇOK daha az verimli olduğu da unutulmamalıdır ... Python 3.5GB dosyayı 5 dakika içinde bitirirken, R yaklaşık 60 dakika sürer ... ama sahip olduğunuz tek şey R ise, o zaman bu bilettir.

## Open a connection separately to hold the cursor position
file.in <- file('bad_data.txt', 'rt')
file.out <- file('chopped_data.txt', 'wt')
line <- readLines(file.in, n=1)
line.split <- strsplit(line, ';')
# Stitching together only the columns we want
cat(line.split[[1]][1:5], line.split[[1]][8], sep = ';', file = file.out, fill = TRUE)
## Use a loop to read in the rest of the lines
line <- readLines(file.in, n=1)
while (length(line)) {
  line.split <- strsplit(line, ';')
  if (length(line.split[[1]]) > 1) {
    if (line.split[[1]][3] == '2009') {
        cat(line.split[[1]][1:5], line.split[[1]][8], sep = ';', file = file.out, fill = TRUE)
    }
  }
  line<- readLines(file.in, n=1)
}
close(file.in)
close(file.out)

Yaklaşıma Göre Başarısızlıklar:

  • sqldf
    • Veriler iyi biçimlendirilmişse, gelecekte bu tür problemler için kesinlikle kullanacağım şey budur. Ancak, değilse, SQLite tıkanır.
  • Harita indirgeme
    • Dürüst olmak gerekirse, doktorlar bu konuda beni biraz korkuttu, bu yüzden denemeye başlamadım. Nesnenin de hafızada olmasını gerektiriyor gibi görünüyordu, bu durum böyle olsaydı bu noktayı yenebilirdi.
  • büyük hafıza
    • Bu yaklaşım verilere net bir şekilde bağlanmıştır, ancak aynı anda yalnızca bir türü işleyebilir. Sonuç olarak, büyük bir masaya konulduğunda tüm karakter vektörlerim düştü. Gelecek için büyük veri kümeleri tasarlamam gerekirse, yalnızca bu seçeneği canlı tutmak için sayıları kullanmayı düşünürdüm.
  • taramak
    • Tarama, büyük bellekle benzer tür sorunlara sahip gibi görünüyordu, ancak readLines'in tüm mekanikleriyle. Kısacası, bu sefer faturaya uymadı.

4
Kriterleriniz yeterince basitse , CSV'nin doğrudan okuyabileceğiniz parçalanmış bir sürümünü kullanmak sedve / veya awkoluşturmaktan büyük olasılıkla kurtulabilirsiniz . Bu bir cevaptan çok bir geçici çözüm olduğu için, bunu bir yorum olarak bırakacağım.
Hank Gay

Hank katılıyorum - bu iş için doğru aracı kullanmak gerektiğini ve alakasız satırları kaldırarak basit veri temizleme / eğer / sütunlar hat akışı araçları gibi komut sıralama / sed / awk büyük ve olacak şekilde daha az Ar daha yoğun kaynak veya python - dosya formatınızın bir örneğini verirseniz, muhtemelen bir örnek verebiliriz
Aaron Statham

Harika. Ne keşfettiğinizi bize bildirin.
Shane

@Hank & Aaron: Genelde iş için doğru aracı kullanmaktan yanayım, ancak bunun iş yerinde bir Windows makinesinde olduğu ve giderken R öğreniyorum, bunun en iyi uygulamalardan vazgeçmek için iyi bir egzersiz olacağını düşündüm ve bunu mümkünse yalnızca R olarak deneyin.
FTWynn

3
İleride başvurmak için data.table R paketine bakın. freadFonksiyon daha hızlıdır read.table. x = fread(file_path_here, data.table=FALSE)Bir data.framenesne olarak yüklemek gibi bir şey kullanın .
paleo13

Yanıtlar:


40

İle denemem readLines. Bu kod parçası csvseçilen yıllar ile yaratılır.

file_in <- file("in.csv","r")
file_out <- file("out.csv","a")
x <- readLines(file_in, n=1)
writeLines(x, file_out) # copy headers

B <- 300000 # depends how large is one pack
while(length(x)) {
    ind <- grep("^[^;]*;[^;]*; 20(09|10)", x)
    if (length(ind)) writeLines(x[ind], file_out)
    x <- readLines(file_in, n=B)
}
close(file_in)
close(file_out)

Bu neredeyse tam olarak yazdığım şeydi. Bellek kısıtlamaları, karışık türler ve hatalı biçimlendirilmiş satırlar göz önüne alındığında bunun en iyi yanıt olacağını düşünüyorum.
FTWynn

10

Bu konuda uzman değilim, ancak MapReduce'u denemeyi düşünebilirsiniz , bu temelde "böl ve yönet" yaklaşımını benimsemek anlamına gelir. R'nin bunun için birkaç seçeneği vardır:

  1. mapReduce (saf R)
  2. RHIPE ( Hadoop kullanır ); alt küme dosyalarının bir örneği için belgelerdeki örnek 6.2.2'ye bakın

Alternatif olarak, R, belleğin dışına (diske) giden büyük verilerle başa çıkmak için birkaç paket sağlar. Muhtemelen tüm veri setini bir bigmemorynesneye yükleyebilir ve indirgemeyi tamamen R içinde yapabilirsiniz. Bunu halletmek için bir dizi araç için http://www.bigmemory.org/ adresine bakın .


İyi bir öneri, ancak MapReduce ve benzeri konusunda pek tecrübem yok. Bunu okumam gerekecek.
FTWynn

bigmemorybu durumda ilk önce denemeniz daha kolay olabilir.
Shane

10

R'de her seferinde bir parçayı dosyalarda okumanın benzer bir yolu var mı?

Evet. ReadChar () işlevi, bunların boş sonlandırılmış varsayarak olmayan karakter bir blok okuyacaktır. Bir seferde bir satırdaki verileri okumak istiyorsanız, readLines () kullanabilirsiniz . Bir blok veya satır okursanız, bir işlem yapın ve ardından verileri yazın, hafıza sorununu önleyebilirsiniz. Amazon'un EC2'sinde büyük bir bellek örneğini ateşlemek istiyorsanız 64 GB'a kadar RAM alabilirsiniz. Bu, dosyanızı ve verileri işlemek için bolca yer tutmalıdır.

Daha fazla hıza ihtiyacınız varsa, Shane'in Map Reduce'u kullanma tavsiyesi çok iyidir. Ancak EC2'de büyük bir bellek örneği kullanma yoluna giderseniz, bir makinedeki tüm çekirdekleri kullanmak için çok çekirdekli pakete bakmalısınız.

Kendinizi çok sayıda sınırlandırılmış veriyi R'ye okumak istiyorsanız, en azından R'den doğrudan sqldf'ye aktarmanıza ve ardından veriler üzerinde R içinde işlem yapmanıza izin veren sqldf paketini araştırmalısınız. Bu önceki soruda belirtildiği gibi, verileri R'ye aktarmanın en hızlı yollarından biri .


EC2 örneğini aklımda tutacağım, ancak şu anda masaüstüme bağlı kalmam gerekiyor ve bu 2 GB RAM. sqldf kesinlikle aklımdaki gibi görünüyor. Ancak, hatalı biçimlendirilmiş satırlarda da boğuluyor (17 sütun olmalı, ancak birkaç bin satırda yalnızca bir tane var). Bu başka bir ön işleme yöntemi mi gerektiriyor yoksa eksik olduğum bir seçenek var mı?
FTWynn

6

Yalnızca muazzam metin dosyalarından istediğiniz değişkenleri okumanıza izin veren colbycol adında yepyeni bir paket var:

http://colbycol.r-forge.r-project.org/

Herhangi bir argümanı read.table'a iletir, bu nedenle kombinasyon oldukça sıkı bir şekilde alt kümelenmenize izin vermelidir.



6

Peki ya kullanmak readrve read_*_chunkedaile?

Yani senin durumunda:

testfile.csv

County; State; Year; Quarter; Segment; Sub-Segment; Sub-Sub-Segment; GDP
Ada County;NC;2009;4;FIRE;Financial;Banks;80.1
Ada County;NC;2010;1;FIRE;Financial;Banks;82.5
lol
Ada County;NC;2013;1;FIRE;Financial;Banks;82.5

Gerçek kod

require(readr)
f <- function(x, pos) subset(x, Year %in% c(2009, 2010))
read_csv2_chunked("testfile.csv", DataFrameCallback$new(f), chunk_size = 1)

Bu f, sütun adlarını hatırlayarak ve filtrelenen sonuçları sonunda birleştirerek her bir parça için geçerlidir . ?callbackBu örneğin kaynağının hangisi olduğuna bakın .

Bunun sonucu:

# A tibble: 2 × 8
      County State  Year Quarter Segment `Sub-Segment` `Sub-Sub-Segment`   GDP
*      <chr> <chr> <int>   <int>   <chr>         <chr>             <chr> <dbl>
1 Ada County    NC  2009       4    FIRE     Financial             Banks   801
2 Ada County    NC  2010       1    FIRE     Financial             Banks   825

Hatta artırabilirsiniz chunk_sizeancak bu örnekte sadece 4 satır var.


5

Sen olabilir SQLite veritabanına veri almak ve sonra kullanmak RSQLite belirli alt kümelere.


İyi bir plan, ancak sqldf'nin esasen perde arkasında yaptığı şey bu olduğundan, bunu tercih ederim. Düz RSQLite kullanıyorsanız, hatalı biçimlendirilmiş satırları işlemenin daha iyi bir yolu yoksa?
FTWynn


3

Kendinizi MS Access sınırlamalarından korumak için MySQL veya PostgreSQL'e geçebilirsiniz.

R'yi bu sistemlere DBI (CRAN'da mevcuttur) tabanlı bir veritabanı konektörü ile bağlamak oldukça kolaydır .


Daha iyi veritabanı araçlarını kullanmak için dokunun, ancak bu idari bir zorluk içereceği için (büyük şirketlerde bu yönetim düzenlemelerini sevmek zorundayım), sahip olduğum şeye bağlı kalmaya çalışıyorum. Ayrıca, aldığım metin dosyası arasında olabildiğince az dönüşüm sağlamayı hedefliyorum.
FTWynn

3

scan () hem bir satır argümanı hem de bir atlama argümanı içerir. Bunu bir defada satır yığınları halinde okumak, uygun olup olmadığını görmek için tarihi kontrol etmek için kullanmanın bir nedeni var mı? Girdi dosyası tarihe göre sıralanırsa, ileride süreci hızlandıracak atlama ve satır satırlarınızın ne olması gerektiğini size söyleyen bir dizin depolayabilirsiniz.


Kontrol edeceğim, ancak dosya tarih gibi yararlı herhangi bir şeye göre sıralanmamış. Sağlayıcılar, belirli bir ülkenin hangi bölgeye göre sıralamanın daha önemli olduğunu düşünüyor. / Sigh ...
FTWynn

Sanırım onun önerisini yanlış anladınız: dosya öbeklerinizi parçalar halinde okuyun ve her parçadan yalnızca ihtiyacınız olan satırları çıkarın. Dosyaların sipariş edilmesine gerek yoktur.
Karl Forner

2

Bugünlerde 3,5 GB gerçekten o kadar büyük değil, Amazon bulutunda 244 GB RAM (r3.8xlarge) içeren bir makineye 2,80 $ / saat karşılığında erişebiliyorum. Büyük veri türü çözümleri kullanarak problemi nasıl çözeceğinizi anlamanız kaç saatinizi alacak? Zamanınızın değeri ne kadar? Evet, AWS'yi nasıl kullanacağınızı anlamanız bir veya iki saatinizi alacak - ancak ücretsiz bir katmanda temel bilgileri öğrenebilir, verileri yükleyebilir ve çalışıp çalışmadığını kontrol etmek için R'ye ilk 10 bin satırı okuyabilirsiniz ve ardından bir r3.8xlarge gibi büyük bellek örneği ve hepsini içinde okuyun! Sadece benim 2c.


Aralık 2020'de AWS EC2'de 24 TB'lık bir makine edinmek mümkün! Bugünlerde sunucumda düzenli olarak 20GB CSV dosyalarını okuyorum ve bu biraz zaman alıyor :). Tidyverse için şükürler olsun!
Sean

0

Şimdi, 2017, kıvılcım ve kıvılcım için gitmeyi öneririm.

  • sözdizimi dplyr benzeri basit bir şekilde yazılabilir

  • küçük belleğe oldukça iyi uyuyor (2017 anlamında küçük)

Ancak, başlamak korkutucu bir deneyim olabilir ...


(SparklyR paketi mümkün 's sözdizimi hakkında fazla bilgi sahibi olmadan ışıltılı kullanmayı kolaylaştırır.)
Michael

-3

Bir DB için giderdim ve sonra ihtiyaç duyduğunuz örnekleri DBI aracılığıyla çıkarmak için bazı sorgular yaparım

Lütfen 3,5 GB csv dosyasını SQLite'a aktarmaktan kaçının. Veya BÜYÜK db'nizin SQLite sınırlarına uyup uymadığını iki kez kontrol edin, http://www.sqlite.org/limits.html

Sahip olduğunuz lanet olası büyük bir DB. Hıza ihtiyacınız varsa MySQL'e giderim. Ancak, ithalatın bitmesi için saatlerce beklemeye hazırlıklı olun. Alışılmadık bir donanıma sahip değilseniz veya gelecekten yazmıyorsanız ...

Amazon'un EC2'si, R ve MySQL çalıştıran bir sunucuyu başlatmak için de iyi bir çözüm olabilir.

benim iki mütevazı bozukluğum değerinde.


18
3.5 Gb, sqlite için ne kadar büyük? Uygun bir dosya sistemi kullandığınız sürece sorun olmamalıdır (Tek kullanıcılı uygulamalar için düzenli olarak> 30 Gb sqlite dbs kullanıyorum)
Aaron Statham
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.