Membuka file 20GB untuk analisis dengan panda

33

Saat ini saya mencoba untuk membuka file dengan panda dan python untuk tujuan pembelajaran mesin, akan ideal bagi saya untuk memiliki semuanya dalam DataFrame. Sekarang file tersebut berukuran 18GB dan RAM saya 32 GB tetapi saya terus mendapatkan kesalahan memori.

Dari pengalaman Anda, mungkinkah? Jika tidak, apakah Anda tahu cara yang lebih baik untuk mengatasi ini? (hive table? menambah ukuran RAM saya menjadi 64? buat database dan akses dari python)

Hari Prasad
sumber
Saya pernah mengalami masalah yang sama, saya sarankan Anda meningkatkan swap, paging, ukuran hard drive Anda.
Media
Aturan praktis saat memuat data pandasadalah, Anda harus memiliki RAM 5-10 kali lebih banyak. Saya sarankan melakukan inplaceoperasi, secara eksplisit memanggil garbage.collectoruntuk mendelegasikan objek.
Kiritee Gak
4
Jadikan pertanyaan ini lebih baik dengan menyatakan tujuan akhir Anda. Apakah Anda melakukan analisis data eksplorasi, pembersihan data, pelatihan model, atau apa? Jenis data apa?
Pete
1
Sudahkah Anda mempertimbangkan untuk menggunakan dask ?
rpanai

Jawaban:

32

Jika ini file csv dan Anda tidak perlu mengakses semua data sekaligus saat melatih algoritme Anda, Anda dapat membacanya dalam potongan. The pandas.read_csvMetode memungkinkan Anda untuk membaca file dalam potongan seperti ini:

import pandas as pd
for chunk in pd.read_csv(<filepath>, chunksize=<your_chunksize_here>)
    do_processing()
    train_algorithm()

Berikut adalah dokumentasi metode ini

Olel Daniel
sumber
apakah ini berlaku untuk file zip juga?
James Wierzba
Ini akan berfungsi jika file zip juga file csv, Anda harus meneruskan tipe kompresi sebagai argumen ke metode
Olel Daniel
22

Ada dua kemungkinan: Anda harus memiliki semua data dalam memori untuk diproses (mis. Algoritma pembelajaran mesin Anda ingin menggunakan semuanya sekaligus), atau Anda dapat melakukannya tanpa itu (mis. Algoritma Anda hanya membutuhkan sampel baris atau kolom sekaligus).

Dalam kasus pertama, Anda harus menyelesaikan masalah memori . Tingkatkan ukuran memori Anda, sewa mesin cloud memori tinggi, gunakan operasi inplace, berikan informasi tentang jenis data yang Anda baca, pastikan untuk menghapus semua variabel yang tidak digunakan dan mengumpulkan sampah, dll.

Sangat mungkin bahwa 32GB RAM tidak akan cukup bagi Pandas untuk menangani data Anda. Perhatikan bahwa integer "1" hanya satu byte ketika disimpan sebagai teks tetapi 8 byte ketika direpresentasikan sebagai int64(yang merupakan default ketika Pandas membacanya dari teks). Anda dapat membuat contoh yang sama dengan angka floating point "1.0" yang diperluas dari string 3-byte ke 8-byte float64secara default. Anda dapat memenangkan ruang dengan membiarkan Panda tahu persis jenis mana yang digunakan untuk setiap kolom dan memaksa representasi sekecil mungkin, tetapi kami bahkan tidak mulai berbicara tentang struktur data Python di atas sini, yang dapat menambahkan satu atau dua pointer tambahan di sini atau di sana dengan mudah , dan pointer masing-masing 8 byte pada mesin 64-bit.

Untuk meringkas: tidak, 32GB RAM mungkin tidak cukup untuk Pandas untuk menangani file 20GB.

Dalam kasus kedua (yang lebih realistis dan mungkin berlaku untuk Anda), Anda perlu menyelesaikan masalah manajemen data . Memang, harus memuat semua data saat Anda benar-benar hanya membutuhkan bagian untuk diproses, mungkin merupakan tanda manajemen data yang buruk. Ada beberapa opsi di sini:

  1. Gunakan database SQL. Jika Anda bisa, itu hampir selalu menjadi pilihan pertama dan solusi yang cukup nyaman. 20GB terdengar seperti ukuran yang paling banyak ditangani oleh basis data SQL tanpa perlu didistribusikan bahkan pada laptop (kelas atas). Anda dapat mengindeks kolom, melakukan agregasi dasar melalui SQL, dan memasukkan subsampel yang diperlukan ke dalam Pandas untuk pemrosesan yang lebih kompleks menggunakan yang sederhana pd.read_sql. Memindahkan data ke database juga akan memberi Anda kesempatan untuk memikirkan jenis dan ukuran data aktual kolom Anda.

  2. Jika data Anda sebagian besar numerik (yaitu array atau tensor), Anda dapat mempertimbangkan untuk menahannya dalam format HDF5 (lihat PyTables ), yang memungkinkan Anda dengan mudah membaca hanya potongan-potongan array besar yang diperlukan dari disk. Numpy.save dan numpy.load dasar mencapai efek yang sama melalui pemetaan memori array pada disk juga. Untuk GIS dan data raster terkait ada database khusus , yang mungkin tidak terhubung ke panda secara langsung seperti SQL, tetapi juga memungkinkan Anda melakukan irisan dan kueri dengan cukup mudah.

  3. Panda tidak mendukung pemetaan memori "parsial" seperti HDF5 atau array numpy, sejauh yang saya tahu. Jika Anda masih menginginkan semacam solusi "pure-panda", Anda dapat mencoba mengatasinya dengan "sharding": baik menyimpan kolom tabel besar Anda secara terpisah (misalnya dalam file terpisah atau dalam "tabel" terpisah dari HDF5 tunggal) file) dan hanya memuat yang diperlukan sesuai permintaan, atau menyimpan potongan baris secara terpisah. Namun, Anda kemudian perlu menerapkan logika untuk memuat potongan yang diperlukan, sehingga menciptakan kembali sepeda yang sudah diimplementasikan di sebagian besar basis data SQL, jadi mungkin opsi 1 masih akan lebih mudah di sini. Jika data Anda datang dalam CSV, Anda dapat memprosesnya dalam potongan dengan menentukan chunksizeparameter pd.read_csv.

KT.
sumber
5
Sesuatu yang harus disebutkan dalam "kasus pertama" adalah bahwa jika OP memiliki banyak entri dengan nilai yang sama dalam data (seperti nol), data dikatakan jarang dan matriks jarang jarang dapat digunakan daripada panda dataframe - data jarang membutuhkan lebih sedikit memori.
Ricardo Cruz
9

Saya baru saja mengalami masalah ini beberapa hari yang lalu! Tidak yakin apakah ini membantu dalam kasus spesifik Anda karena Anda tidak memberikan begitu banyak detail, tetapi situasi saya adalah bekerja offline pada dataset 'besar'. Data diperoleh sebagai file CSV 20GB gzipped dari meter energi, data deret waktu pada interval beberapa detik.

File IO:

data_root = r"/media/usr/USB STICK"
fname = r"meters001-050-timestamps.csv.gz"
this_file = os.path.join(data_root,fname)
assert os.path.exists(this_file), this_file
this_file

Buat chunk iterator langsung di atas file gzip (jangan unzip!)

cols_to_keep = [0,1,2,3,7]
column_names = ['METERID','TSTAMP','ENERGY','POWER_ALL','ENERGY_OUT',]
parse_dates = ['TSTAMP']
dtype={'METERID': np.int32, 
       'ENERGY': np.int32,
       'POWER_ALL': np.int32,
       'ENERGY_OUT': np.int32,
      }
df_iterator = pd.read_csv(this_file, 
                        skiprows=0, 
                        compression='gzip',
                        chunksize=1000000, 
                        usecols=cols_to_keep,
                        delimiter=";",
                        header=None,
                        names = column_names,
                      dtype=dtype,
                     parse_dates=parse_dates,
                     index_col=1,
                     )

Iterate di atas potongan

new_df = pd.DataFrame()
count = 0
for df in df_iterator:
    chunk_df_15min = df.resample('15T').first()
    #chunk_df_30min = df.resample('30T').first()
    #chunk_df_hourly = df.resample('H').first()
    this_df = chunk_df_15min
    this_df = this_df.pipe(lambda x: x[x.METERID == 1])
    #print("chunk",i)
    new_df = pd.concat([new_df,chunk_df_15min])
    print("chunk",count, len(chunk_df_15min), 'rows added')
    #print("chunk",i, len(temp_df),'rows added')
    #break
    count += 1

Di dalam chunk loop, saya melakukan beberapa penyaringan dan pengambilan sampel ulang tepat waktu. Melakukan ini, saya mengurangi ukuran dari 20GB menjadi beberapa ratus MB HDF5 untuk eksplorasi data offline lebih lanjut.

Marcus Jones
sumber
5

Dalam pengalaman saya, menginisialisasi read_csv()dengan parameter low_memory=Falsecenderung membantu saat membaca dalam file besar. Saya tidak berpikir Anda telah menyebutkan jenis file yang Anda baca, jadi saya tidak yakin bagaimana ini berlaku untuk situasi Anda.

rantaiD
sumber
1

Jika file Anda adalah CSV, maka Anda cukup melakukannya di Chunk by Chunk. Anda cukup melakukannya:

import pandas as pd
for chunk in pd.read_csv(FileName, chunksize=ChunkSizeHere)
(Do your processing and training here)
Abdul
sumber