Pekerjaan "Data besar" mengalir menggunakan panda

982

Saya telah mencoba mencari jawaban untuk pertanyaan ini selama berbulan-bulan sambil belajar panda. Saya menggunakan SAS untuk pekerjaan saya sehari-hari dan itu sangat bagus untuk itu dukungan di luar inti. Namun, SAS mengerikan sebagai bagian dari perangkat lunak karena berbagai alasan lainnya.

Suatu hari saya berharap untuk mengganti penggunaan SAS saya dengan python dan panda, tapi saat ini saya kekurangan alur kerja out-of-core untuk dataset besar. Saya tidak berbicara tentang "data besar" yang memerlukan jaringan terdistribusi, melainkan file yang terlalu besar untuk muat di memori tetapi cukup kecil untuk muat di hard-drive.

Pikiran pertama saya adalah menggunakan HDFStoreuntuk menyimpan dataset besar pada disk dan hanya menarik bagian yang saya butuhkan ke dalam kerangka data untuk dianalisis. Yang lain menyebutkan MongoDB sebagai alternatif yang lebih mudah digunakan. Pertanyaan saya adalah ini:

Apa saja alur kerja praktik terbaik untuk mencapai yang berikut ini:

  1. Memuat file rata ke dalam struktur basis data disk permanen
  2. Meminta basis data itu untuk mengambil data untuk dimasukkan ke dalam struktur data panda
  3. Memperbarui database setelah memanipulasi potongan dalam panda

Contoh dunia nyata akan sangat dihargai, terutama dari siapa pun yang menggunakan panda pada "data besar".

Edit - contoh bagaimana saya ingin ini berfungsi:

  1. Mengimpor file flat besar secara besar-besaran dan menyimpannya dalam struktur basis data on-disk yang permanen. File-file ini biasanya terlalu besar untuk muat di memori.
  2. Untuk menggunakan Panda, saya ingin membaca himpunan bagian dari data ini (biasanya hanya beberapa kolom pada satu waktu) yang dapat ditampung dalam memori.
  3. Saya akan membuat kolom baru dengan melakukan berbagai operasi pada kolom yang dipilih.
  4. Saya kemudian harus menambahkan kolom baru ini ke dalam struktur basis data.

Saya mencoba menemukan cara praktik terbaik untuk melakukan langkah-langkah ini. Membaca tautan tentang panda dan pytables tampaknya menambahkan kolom baru bisa menjadi masalah.

Sunting - Menanggapi pertanyaan Jeff secara khusus:

  1. Saya sedang membangun model risiko kredit konsumen. Jenis data termasuk telepon, SSN dan karakteristik alamat; nilai properti; informasi yang merendahkan seperti catatan kriminal, kebangkrutan, dll ... Kumpulan data yang saya gunakan setiap hari rata-rata memiliki hampir 1.000 hingga 2.000 bidang data campuran: variabel kontinu, nominal dan ordinal dari data numerik dan karakter. Saya jarang menambahkan baris, tetapi saya melakukan banyak operasi yang membuat kolom baru.
  2. Operasi tipikal melibatkan menggabungkan beberapa kolom menggunakan logika kondisional ke dalam kolom gabungan yang baru. Sebagai contoh if var1 > 2 then newvar = 'A' elif var2 = 4 then newvar = 'B',. Hasil dari operasi ini adalah kolom baru untuk setiap catatan dalam dataset saya.
  3. Akhirnya, saya ingin menambahkan kolom baru ini ke dalam struktur data pada disk. Saya akan mengulangi langkah 2, mengeksplorasi data dengan tab silang dan statistik deskriptif yang berusaha menemukan hubungan yang menarik, intuitif dengan model.
  4. File proyek tipikal biasanya sekitar 1GB. File disusun sedemikian rupa di mana baris terdiri dari catatan data konsumen. Setiap baris memiliki jumlah kolom yang sama untuk setiap catatan. Ini akan selalu menjadi masalah.
  5. Sangat jarang bahwa saya akan subset oleh baris ketika membuat kolom baru. Namun, sangat umum bagi saya untuk membuat subset pada baris ketika membuat laporan atau menghasilkan statistik deskriptif. Misalnya, saya mungkin ingin membuat frekuensi sederhana untuk lini bisnis tertentu, misalnya kartu kredit Ritel. Untuk melakukan ini, saya hanya akan memilih catatan-catatan di mana garis bisnis = ritel di samping kolom mana pun yang ingin saya laporkan. Ketika membuat kolom baru, saya akan menarik semua baris data dan hanya kolom yang saya butuhkan untuk operasi.
  6. Proses pemodelan mengharuskan saya menganalisis setiap kolom, mencari hubungan yang menarik dengan beberapa variabel hasil, dan membuat kolom gabungan baru yang menggambarkan hubungan tersebut. Kolom yang saya jelajahi biasanya dilakukan dalam set kecil. Sebagai contoh, saya akan fokus pada satu set katakan 20 kolom hanya berurusan dengan nilai properti dan amati bagaimana mereka berhubungan dengan default pada pinjaman. Setelah itu dieksplorasi dan kolom baru dibuat, saya kemudian pindah ke grup kolom lain, katakanlah pendidikan perguruan tinggi, dan ulangi prosesnya. Apa yang saya lakukan adalah membuat variabel kandidat yang menjelaskan hubungan antara data saya dan beberapa hasil. Di akhir proses ini, saya menerapkan beberapa teknik pembelajaran yang membuat persamaan dari kolom-kolom majemuk tersebut.

Jarang sekali saya menambahkan baris ke dataset. Saya hampir selalu akan membuat kolom baru (variabel atau fitur dalam statistik / bahasa pembelajaran mesin).

Zelazny7
sumber
1
Apakah rasio ukuran inti / ukuran penuh 1%, 10%? Apakah itu penting - jika Anda bisa mengompres cols ke int8, atau memfilter baris yang berisik, apakah itu akan mengubah loop komputasi-think Anda dari jam katakan menjadi menit? (Juga tambahkan tag besar-data.)
denis
1
Menyimpan float32 alih-alih float64, dan int8 jika memungkinkan, harus sepele (tidak tahu alat / fungsi apa yang mengapung float64 secara internal)
denis
dapatkah Anda membagi tugas menjadi beberapa bagian pekerjaan?
Andrew Scott Evans
1
solusi 2019 yang bagus untuk melakukan panda seperti operasi pada data "sedang" yang tidak muat dalam memori adalah dask
lunguini
Ada alternatif untuk python + panda yang Anda mungkin ingin mempertimbangkan melihat karena Anda baru memulai. Pertimbangkan fakta bahwa Python adalah bahasa pemrograman untuk tujuan umum (bukan DSL untuk munging dan analisis data) dan panda adalah pustaka yang ditempel di atasnya. Saya akan mempertimbangkan melihat R atau kdb.
Henry Henrinson

Jawaban:

622

Saya secara rutin menggunakan puluhan gigabyte data hanya dengan cara ini misalnya saya punya tabel pada disk yang saya baca melalui query, membuat data dan menambahkan kembali.

Ada baiknya membaca dokumen dan terlambat di utas ini untuk beberapa saran tentang cara menyimpan data Anda.

Detail yang akan memengaruhi cara Anda menyimpan data, seperti:
Berikan detail sebanyak mungkin; dan saya dapat membantu Anda mengembangkan struktur.

  1. Ukuran data, # baris, kolom, tipe kolom; apakah Anda menambahkan baris, atau hanya kolom?
  2. Seperti apa operasi tipikal itu. Misalnya, melakukan kueri pada kolom untuk memilih sekelompok baris dan kolom tertentu, lalu melakukan operasi (dalam memori), membuat kolom baru, simpan ini.
    (Memberikan contoh mainan dapat memungkinkan kami untuk menawarkan rekomendasi yang lebih spesifik.)
  3. Setelah proses itu, lalu apa yang Anda lakukan? Apakah langkah 2 ad hoc, atau dapat diulang?
  4. Input file flat: berapa banyak, ukuran total kasar dalam Gb. Bagaimana ini dikelola misalnya dengan catatan? Apakah masing-masing berisi bidang yang berbeda, atau apakah mereka memiliki beberapa catatan per file dengan semua bidang di setiap file?
  5. Apakah Anda pernah memilih subset baris (catatan) berdasarkan kriteria (mis. Pilih baris dengan bidang A> 5)? dan kemudian melakukan sesuatu, atau Anda hanya memilih bidang A, B, C dengan semua catatan (dan kemudian melakukan sesuatu)?
  6. Apakah Anda 'mengerjakan' semua kolom Anda (dalam grup), atau adakah proporsi yang baik yang hanya dapat Anda gunakan untuk laporan (mis. Anda ingin menyimpan data di sekitar, tetapi tidak perlu menarik kejelasan kolom itu sampai waktu hasil akhir)?

Larutan

Pastikan Anda memiliki panda setidaknya0.10.1 diinstal.

Baca iterasi file chunk-by-chunk dan beberapa tabel query .

Karena pytables dioptimalkan untuk beroperasi pada baris-bijaksana (yang merupakan permintaan Anda), kami akan membuat tabel untuk setiap kelompok bidang. Dengan cara ini mudah untuk memilih sekelompok kecil bidang (yang akan bekerja dengan tabel besar, tetapi lebih efisien untuk melakukannya dengan cara ini ... Saya pikir saya mungkin dapat memperbaiki batasan ini di masa depan ... ini adalah lebih intuitif bagaimanapun):
(Berikut ini adalah kodesemu.)

import numpy as np
import pandas as pd

# create a store
store = pd.HDFStore('mystore.h5')

# this is the key to your storage:
#    this maps your fields to a specific group, and defines 
#    what you want to have as data_columns.
#    you might want to create a nice class wrapping this
#    (as you will want to have this map and its inversion)  
group_map = dict(
    A = dict(fields = ['field_1','field_2',.....], dc = ['field_1',....,'field_5']),
    B = dict(fields = ['field_10',......        ], dc = ['field_10']),
    .....
    REPORTING_ONLY = dict(fields = ['field_1000','field_1001',...], dc = []),

)

group_map_inverted = dict()
for g, v in group_map.items():
    group_map_inverted.update(dict([ (f,g) for f in v['fields'] ]))

Membaca dalam file dan membuat penyimpanan (pada dasarnya melakukan apa yang append_to_multipledilakukan):

for f in files:
   # read in the file, additional options may be necessary here
   # the chunksize is not strictly necessary, you may be able to slurp each 
   # file into memory in which case just eliminate this part of the loop 
   # (you can also change chunksize if necessary)
   for chunk in pd.read_table(f, chunksize=50000):
       # we are going to append to each table by group
       # we are not going to create indexes at this time
       # but we *ARE* going to create (some) data_columns

       # figure out the field groupings
       for g, v in group_map.items():
             # create the frame for this group
             frame = chunk.reindex(columns = v['fields'], copy = False)    

             # append it
             store.append(g, frame, index=False, data_columns = v['dc'])

Sekarang Anda memiliki semua tabel dalam file (sebenarnya Anda bisa menyimpannya dalam file terpisah jika Anda mau, Anda mungkin harus menambahkan nama file ke group_map, tetapi mungkin ini tidak perlu).

Ini adalah cara Anda mendapatkan kolom dan membuat yang baru:

frame = store.select(group_that_I_want)
# you can optionally specify:
# columns = a list of the columns IN THAT GROUP (if you wanted to
#     select only say 3 out of the 20 columns in this sub-table)
# and a where clause if you want a subset of the rows

# do calculations on this frame
new_frame = cool_function_on_frame(frame)

# to 'add columns', create a new group (you probably want to
# limit the columns in this new_group to be only NEW ones
# (e.g. so you don't overlap from the other tables)
# add this info to the group_map
store.append(new_group, new_frame.reindex(columns = new_columns_created, copy = False), data_columns = new_columns_created)

Ketika Anda siap untuk post_processing:

# This may be a bit tricky; and depends what you are actually doing.
# I may need to modify this function to be a bit more general:
report_data = store.select_as_multiple([groups_1,groups_2,.....], where =['field_1>0', 'field_1000=foo'], selector = group_1)

Tentang data_columns, Anda sebenarnya tidak perlu mendefinisikan ANY data_columns; mereka memungkinkan Anda untuk memilih sub-baris berdasarkan pada kolom. Misalnya sesuatu seperti:

store.select(group, where = ['field_1000=foo', 'field_1001>0'])

Mereka mungkin paling menarik bagi Anda dalam tahap pembuatan laporan akhir (pada dasarnya kolom data dipisahkan dari kolom lain, yang mungkin agak berdampak pada efisiensi jika Anda mendefinisikan banyak).

Anda juga mungkin ingin:

  • buat fungsi yang mengambil daftar bidang, mencari grup di groups_map, lalu memilih ini dan menggabungkan hasilnya sehingga Anda mendapatkan frame yang dihasilkan (ini pada dasarnya apa yang dilakukan select_as_multiple). Dengan cara ini strukturnya akan cukup transparan bagi Anda.
  • indeks pada kolom data tertentu (membuat pengelompokan baris lebih cepat).
  • aktifkan kompresi.

Beri tahu saya jika Anda memiliki pertanyaan!

Jeff
sumber
5
Terima kasih atas tautannya. Tautan kedua membuat saya sedikit khawatir bahwa saya tidak dapat menambahkan kolom baru ke tabel di HDFStore? Apakah itu benar? Juga, saya menambahkan contoh bagaimana saya akan menggunakan pengaturan ini.
Zelazny7
4
Struktur aktual dalam hdf terserah Anda. Pytables berorientasi baris, dengan kolom tetap pada waktu pembuatan. Anda tidak dapat menambahkan kolom setelah tabel dibuat. Namun, Anda bisa membuat tabel baru yang diindeks sama dengan tabel yang ada. (lihat contoh select_as_multiple dalam dokumen). Dengan cara ini Anda bisa membuat objek berukuran sembarang sambil memiliki kueri yang cukup efisien. Cara Anda menggunakan data adalah kunci untuk mengaturnya di disk. Kirimi saya email yang tidak terdaftar dengan kode pseudo dari contoh yang lebih spesifik.
Jeff
1
Saya telah memperbarui pertanyaan saya untuk menanggapi poin detail Anda. Saya akan mengerjakan contoh untuk mengirim Anda keluar daftar. Terima kasih!
Zelazny7
12
@ Jeff, dengan Panda berada di 0,17.x sekarang apakah masalah yang diuraikan di atas telah diselesaikan di Panda?
ctrl-alt-delete
5
@ Jeff tertarik untuk menambahkan pembaruan cepat pada jawaban Anda untuk mempromosikan dask?
Boud
137

Saya pikir jawaban di atas tidak memiliki pendekatan sederhana yang menurut saya sangat berguna.

Ketika saya memiliki file yang terlalu besar untuk dimuat dalam memori, saya memecah file menjadi beberapa file yang lebih kecil (baik dengan baris atau cols)

Contoh: Dalam hal data perdagangan senilai 30 hari ukuran ~ 30GB, saya memecahnya menjadi file per hari ukuran ~ 1GB. Saya kemudian memproses setiap file secara terpisah dan mengumpulkan hasilnya pada akhirnya

Salah satu keuntungan terbesar adalah memungkinkan pemrosesan paralel file (baik beberapa utas atau proses)

Keuntungan lainnya adalah manipulasi file (seperti menambah / menghapus tanggal pada contoh) dapat dilakukan dengan perintah shell biasa, yang tidak mungkin dilakukan dalam format file yang lebih maju / rumit

Pendekatan ini tidak mencakup semua skenario, tetapi sangat berguna dalam banyak skenario

pengguna1827356
sumber
39
Sepakat. Dengan semua hype, mudah untuk melupakan bahwa alat-alat command-line bisa 235x lebih cepat daripada cluster Hadoop
zelusp
84

Sekarang ada, dua tahun setelah pertanyaan, sebuah panda 'out-of-core' setara: dask . Itu sangat baik! Meskipun tidak mendukung semua fungsionalitas panda, Anda dapat melakukannya dengan sangat baik.

Pribadi
sumber
6
dan untuk contoh yang sepenuhnya dikerjakan dengan dask, lihat saja di sini stackoverflow.com/questions/37979167/…
ℕʘʘḆḽḘ
Bergantung pada data Anda, masuk akal untuk memeriksa pistore . Itu bergantung dask.
gies0r
66

Jika kumpulan data Anda antara 1 dan 20GB, Anda harus mendapatkan workstation dengan 48GB RAM. Kemudian Pandas dapat menyimpan seluruh dataset dalam RAM. Saya tahu ini bukan jawaban yang Anda cari di sini, tetapi melakukan komputasi ilmiah pada notebook dengan 4GB RAM tidak masuk akal.

rjurney
sumber
7
"Melakukan komputasi ilmiah pada notebook dengan 4GB RAM tidak masuk akal" Tentukan masuk akal. Saya pikir UNIVAC akan mengambil pandangan yang berbeda. arstechnica.com/tech-policy/2011/09/…
grisaitis
2
Sepakat! cobalah untuk terus bekerja dalam memori meskipun biayanya $$ di muka. Jika pekerjaan Anda menghasilkan pengembalian finansial, maka seiring waktu, Anda akan memulihkan biaya melalui peningkatan efisiensi Anda.
ansonw
2
Melakukan komputasi ilmiah pada workstation dengan 48GB RAM tidak masuk akal.
Yaroslav Nikitenko
4
@YaroslavNikitenko R4.2xlarge dengan 61GB / RAM adalah $ 0,532 / jam. Apa jenis komputasi ilmiah yang Anda lakukan yang tidak begitu berharga? Kedengarannya tidak biasa, jika tidak masuk akal.
rjurney
4
@ rjurney maaf, mungkin saya harus menghapus komentar saya. Penilaian Anda terhadap komputer ilmiah "tidak masuk akal" tampaknya sangat subyektif. Saya melakukan perhitungan ilmiah selama bertahun-tahun di laptop, dan itu tampaknya cukup bagi saya, karena sebagian besar waktu saya menulis kode. Algoritma saya jauh lebih sulit dari sudut pandang pemrograman daripada dari sudut komputasi. Saya juga cukup yakin bahwa untuk menulis algoritma yang skalabel kita tidak harus bergantung pada keterbatasan perangkat keras saat ini. Komentar Anda tentang komputasi orang lain mungkin terdengar agak ofensif (terlepas dari subjektivitas), maukah Anda menghapus beberapa kata ini?
Yaroslav Nikitenko
59

Saya tahu ini adalah utas lama tapi saya pikir perpustakaan Blaze layak untuk dicoba. Itu dibangun untuk situasi semacam ini.

Dari dokumen:

Blaze memperluas kegunaan NumPy dan Panda untuk komputasi terdistribusi dan out-of-core. Blaze menyediakan antarmuka yang mirip dengan NumPy ND-Array atau Pandas DataFrame tetapi memetakan antarmuka yang sudah dikenal ini ke berbagai mesin komputasi lain seperti Postgres atau Spark.

Sunting: Omong-omong, didukung oleh ContinuumIO dan Travis Oliphant, penulis NumPy.

chishaku
sumber
Pustaka lain yang mungkin patut dilihat adalah GraphLab Create: Ini memiliki struktur seperti DataFrame yang efisien yang tidak dibatasi oleh kapasitas memori. blog.dato.com/…
kedap air
52

Ini adalah kasus untuk pymongo. Saya juga telah membuat prototipe menggunakan sql server, sqlite, HDF, ORM (SQLAlchemy) dalam python. Pymongo pertama dan terpenting adalah DB berbasis dokumen, sehingga setiap orang akan menjadi dokumen ( dictatribut). Banyak orang membentuk koleksi dan Anda dapat memiliki banyak koleksi (orang, pasar saham, pendapatan).

pd.dateframe -> pymongo Catatan: Saya menggunakan chunksizedalam read_csvuntuk menyimpannya hingga 5 hingga 10 ribu catatan (pymongo menjatuhkan soket jika lebih besar)

aCollection.insert((a[1].to_dict() for a in df.iterrows()))

kueri: gt = lebih besar dari ...

pd.DataFrame(list(mongoCollection.find({'anAttribute':{'$gt':2887000, '$lt':2889000}})))

.find()mengembalikan sebuah iterator jadi saya biasanya gunakan ichunkeduntuk memotong iterator yang lebih kecil.

Bagaimana dengan bergabung karena saya biasanya mendapatkan 10 sumber data untuk disatukan:

aJoinDF = pandas.DataFrame(list(mongoCollection.find({'anAttribute':{'$in':Att_Keys}})))

lalu (dalam kasus saya kadang-kadang saya harus melakukan ag aJoinDFterlebih dahulu sebelum "dapat digabungkan".)

df = pandas.merge(df, aJoinDF, on=aKey, how='left')

Dan Anda kemudian dapat menulis info baru ke koleksi utama Anda melalui metode pembaruan di bawah ini. (pengumpulan logis vs sumber data fisik).

collection.update({primarykey:foo},{key:change})

Pada pencarian yang lebih kecil, cukup denormalkan. Misalnya, Anda memiliki kode dalam dokumen dan Anda hanya menambahkan teks kode bidang dan melakukan dictpencarian saat Anda membuat dokumen.

Sekarang Anda memiliki dataset yang bagus berdasarkan pada seseorang, Anda dapat melepaskan logika Anda pada setiap kasus dan membuat lebih banyak atribut. Akhirnya, Anda dapat membaca panda indikator kunci maksimal 3 ke memori dan melakukan eksplorasi pivot / ag / data. Ini bekerja untuk saya selama 3 juta catatan dengan angka / teks besar / kategori / kode / mengapung / ...

Anda juga dapat menggunakan dua metode yang dibangun ke dalam MongoDB (kerangka MapReduce dan agregat). Lihat di sini untuk info lebih lanjut tentang kerangka kerja agregat , karena tampaknya lebih mudah daripada MapReduce dan terlihat berguna untuk pekerjaan agregat cepat. Perhatikan saya tidak perlu mendefinisikan bidang atau relasi saya, dan saya bisa menambahkan item ke dokumen. Pada keadaan saat ini dari numpy, panda, python toolset yang berubah dengan cepat, MongoDB membantu saya untuk mulai bekerja :)

brian_the_bungler
sumber
Hi, aku bermain-main dengan contoh Anda juga dan saya mengalami kesalahan ini ketika mencoba untuk memasukkan ke dalam database: In [96]: test.insert((a[1].to_dict() for a in df.iterrows())) --------------- InvalidDocument: Cannot encode object: 0. Ada ide apa yang mungkin salah? Dataframe saya terdiri dari semua int64 dtypes dan sangat sederhana.
Zelazny7
2
Ya saya melakukan hal yang sama untuk rentang DF sederhana dan int64 dari numpy tampaknya mengganggu pymongo. Semua data yang saya mainkan dengan konversi dari CSV (vs artifisial via range ()) dan memiliki tipe yang panjang dan karenanya tidak ada masalah. Dalam numpy Anda dapat mengkonversi tetapi saya melihat itu sebagai pengurang. Saya harus mengakui 10.1 item untuk HDF terlihat menarik.
brian_the_bungler
43

Saya melihat ini agak terlambat, tetapi saya bekerja dengan masalah yang sama (model pembayaran di muka hipotek). Solusi saya adalah dengan melewatkan layer HDFStore panda dan menggunakan pytables lurus. Saya menyimpan setiap kolom sebagai array HDF5 individu di file terakhir saya.

Alur kerja dasar saya adalah pertama-tama mendapatkan file CSV dari database. Saya gzip, jadi tidak sebesar ini. Kemudian saya mengonversinya menjadi file HDF5 berorientasi baris, dengan mengulanginya menggunakan python, mengubah setiap baris menjadi tipe data nyata, dan menulisnya ke file HDF5. Itu membutuhkan waktu puluhan menit, tetapi tidak menggunakan memori apa pun, karena hanya beroperasi baris demi baris. Lalu saya "memindahkan" file HDF5 yang berorientasi baris menjadi file HDF5 yang berorientasi kolom.

Tabel transpos terlihat seperti:

def transpose_table(h_in, table_path, h_out, group_name="data", group_path="/"):
    # Get a reference to the input data.
    tb = h_in.getNode(table_path)
    # Create the output group to hold the columns.
    grp = h_out.createGroup(group_path, group_name, filters=tables.Filters(complevel=1))
    for col_name in tb.colnames:
        logger.debug("Processing %s", col_name)
        # Get the data.
        col_data = tb.col(col_name)
        # Create the output array.
        arr = h_out.createCArray(grp,
                                 col_name,
                                 tables.Atom.from_dtype(col_data.dtype),
                                 col_data.shape)
        # Store the data.
        arr[:] = col_data
    h_out.flush()

Membaca kembali kemudian terlihat seperti:

def read_hdf5(hdf5_path, group_path="/data", columns=None):
    """Read a transposed data set from a HDF5 file."""
    if isinstance(hdf5_path, tables.file.File):
        hf = hdf5_path
    else:
        hf = tables.openFile(hdf5_path)

    grp = hf.getNode(group_path)
    if columns is None:
        data = [(child.name, child[:]) for child in grp]
    else:
        data = [(child.name, child[:]) for child in grp if child.name in columns]

    # Convert any float32 columns to float64 for processing.
    for i in range(len(data)):
        name, vec = data[i]
        if vec.dtype == np.float32:
            data[i] = (name, vec.astype(np.float64))

    if not isinstance(hdf5_path, tables.file.File):
        hf.close()
    return pd.DataFrame.from_items(data)

Sekarang, saya biasanya menjalankan ini pada mesin dengan banyak memori, jadi saya mungkin tidak cukup berhati-hati dengan penggunaan memori saya. Misalnya, secara default operasi pemuatan membaca seluruh kumpulan data.

Ini umumnya bekerja untuk saya, tapi agak kikuk, dan saya tidak bisa menggunakan sihir pytables yang mewah.

Sunting: Keuntungan nyata dari pendekatan ini, daripada array-of-records pytables default, adalah bahwa saya kemudian dapat memuat data ke R menggunakan h5r, yang tidak dapat menangani tabel. Atau, setidaknya, saya tidak dapat membuatnya memuat tabel heterogen.

Johann Hibschman
sumber
maukah Anda berbagi dengan saya beberapa kode Anda? Saya tertarik pada bagaimana Anda memuat data dari beberapa format teks datar tanpa mengetahui tipe data sebelum mendorong ke pytables. Selain itu, sepertinya Anda hanya bekerja dengan data satu jenis. Apakah itu benar?
Zelazny7
1
Pertama-tama, saya menganggap saya tahu jenis kolom sebelum memuat, daripada mencoba menebak dari data. Saya menyimpan file "data spec" JSON dengan nama dan tipe kolom dan menggunakannya saat memproses data. (File ini biasanya berupa output BCP yang mengerikan tanpa label.) Tipe data yang saya gunakan adalah string, float, integer, atau tanggal bulanan. Saya mengubah string menjadi int dengan menyimpan tabel enumerasi dan mengubah tanggal menjadi int (bulan lalu 2000), jadi saya hanya tersisa dengan int dan mengapung dalam data saya, ditambah enumerasi. Saya menyimpan float sebagai float64 sekarang, tetapi saya bereksperimen dengan float32.
Johann Hibschman
1
jika Anda punya waktu, silakan coba ini untuk eksternal compat dengan R: pandas.pydata.org/pandas-docs/dev/… , dan jika Anda mengalami kesulitan, mungkin kita dapat mengubahnya
Jeff
Saya akan mencoba, jika saya bisa. rhdf5 menyakitkan, karena ini adalah paket biokonduktor, bukan hanya menggunakan CRAN seperti h5r. Saya berada di tangan tim arsitektur teknis kami, dan ada beberapa masalah dengan rhdf5 terakhir kali saya memintanya. Bagaimanapun, sepertinya kesalahan untuk pergi berorientasi baris daripada berorientasi kolom dengan toko OLAP, tapi sekarang saya mengoceh.
Johann Hibschman
39

Salah satu trik yang saya temukan bermanfaat untuk kasus penggunaan data yang besar adalah mengurangi volume data dengan mengurangi presisi float menjadi 32-bit. Ini tidak berlaku dalam semua kasus, tetapi dalam banyak aplikasi presisi 64-bit berlebihan dan penghematan memori 2x sepadan. Untuk membuat poin yang jelas semakin jelas:

>>> df = pd.DataFrame(np.random.randn(int(1e8), 5))
>>> df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100000000 entries, 0 to 99999999
Data columns (total 5 columns):
...
dtypes: float64(5)
memory usage: 3.7 GB

>>> df.astype(np.float32).info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100000000 entries, 0 to 99999999
Data columns (total 5 columns):
...
dtypes: float32(5)
memory usage: 1.9 GB
ytsaig
sumber
27

Sebagaimana dicatat oleh orang lain, setelah beberapa tahun, panda setara 'out-of-core' telah muncul: dask . Meskipun dask bukanlah pengganti panda yang drop-in dan semua fungsinya, ia menonjol karena beberapa alasan:

Dask adalah perpustakaan komputasi paralel fleksibel untuk komputasi analitik yang dioptimalkan untuk penjadwalan tugas dinamis untuk beban kerja komputasi interaktif dari koleksi "Big Data" seperti array paralel, kerangka data, dan daftar yang memperluas antarmuka umum seperti NumPy, Pandas, atau iterator Python ke yang lebih besar- dari-memori atau lingkungan terdistribusi dan skala dari laptop ke cluster.

Dask menekankan kebajikan-kebajikan berikut:

  • Akrab: Menyediakan array NumPy yang paralel dan objek DataFrame Pandas
  • Fleksibel: Menyediakan antarmuka penjadwalan tugas untuk lebih banyak beban kerja khusus dan integrasi dengan proyek lain.
  • Asli: Mengaktifkan komputasi terdistribusi dalam Python Murni dengan akses ke tumpukan PyData.
  • Cepat: Beroperasi dengan overhead rendah, latensi rendah, dan serialisasi minimal yang diperlukan untuk algoritma numerik cepat
  • Scales up: Berjalan tangguh pada cluster dengan 1000s core Scales down: Sepele untuk mengatur dan menjalankan pada laptop dalam satu proses
  • Responsif: Dirancang dengan komputasi interaktif, ini memberikan umpan balik dan diagnostik cepat untuk membantu manusia

dan untuk menambahkan contoh kode sederhana:

import dask.dataframe as dd
df = dd.read_csv('2015-*-*.csv')
df.groupby(df.user_id).value.mean().compute()

mengganti beberapa kode panda seperti ini:

import pandas as pd
df = pd.read_csv('2015-01-01.csv')
df.groupby(df.user_id).value.mean()

dan, terutama yang patut diperhatikan, menyediakan concurrent.futuresantarmuka umum infrastruktur untuk pengiriman tugas kustom melalui antarmuka:

from dask.distributed import Client
client = Client('scheduler:port')

futures = []
for fn in filenames:
    future = client.submit(load, fn)
    futures.append(future)

summary = client.submit(summarize, futures)
summary.result()
wp78de
sumber
Saya telah menambahkan jawaban ini sejak posting @Private muncul secara teratur di daftar penghapusan yang disarankan untuk konten dan panjangnya.
wp78de
17

Layak disebutkan di sini Ray juga,
ini adalah kerangka perhitungan terdistribusi, yang memiliki implementasi sendiri untuk panda dengan cara terdistribusi.

Cukup ganti impor panda, dan kodenya harus berfungsi apa adanya:

# import pandas as pd
import ray.dataframe as pd

#use pd as usual

dapat membaca lebih detail di sini:

https://rise.cs.berkeley.edu/blog/pandas-on-ray/

lev
sumber
16

Satu lagi variasi

Banyak operasi yang dilakukan dalam panda juga dapat dilakukan sebagai permintaan db (sql, mongo)

Menggunakan RDBMS atau mongodb memungkinkan Anda untuk melakukan beberapa agregasi di DB Query (yang dioptimalkan untuk data besar, dan menggunakan cache dan indeks secara efisien)

Kemudian, Anda dapat melakukan pemrosesan pos menggunakan panda.

Keuntungan dari metode ini adalah Anda mendapatkan optimisasi DB untuk bekerja dengan data besar, sambil tetap mendefinisikan logika dalam sintaks deklaratif tingkat tinggi - dan tidak harus berurusan dengan detail memutuskan apa yang harus dilakukan dalam memori dan apa yang harus dilakukan inti.

Dan meskipun bahasa query dan panda berbeda, biasanya tidak rumit untuk menerjemahkan bagian dari logika dari satu ke yang lain.

Ophir Yoktan
sumber
11

Pertimbangkan Ruffus jika Anda menggunakan jalur sederhana untuk membuat pipa data yang dipecah menjadi beberapa file yang lebih kecil.

Golf Monkey
sumber
9

Baru-baru ini saya menemukan masalah yang sama. Saya menemukan hanya membaca data dalam potongan dan menambahkannya saat saya menulis dalam potongan untuk csv yang sama berfungsi dengan baik. Masalah saya adalah menambahkan kolom tanggal berdasarkan informasi di tabel lain, menggunakan nilai kolom tertentu sebagai berikut. Ini dapat membantu mereka yang bingung oleh dask dan hdf5 tetapi lebih terbiasa dengan panda seperti saya.

def addDateColumn():
"""Adds time to the daily rainfall data. Reads the csv as chunks of 100k 
   rows at a time and outputs them, appending as needed, to a single csv. 
   Uses the column of the raster names to get the date.
"""
    df = pd.read_csv(pathlist[1]+"CHIRPS_tanz.csv", iterator=True, 
                     chunksize=100000) #read csv file as 100k chunks

    '''Do some stuff'''

    count = 1 #for indexing item in time list 
    for chunk in df: #for each 100k rows
        newtime = [] #empty list to append repeating times for different rows
        toiterate = chunk[chunk.columns[2]] #ID of raster nums to base time
        while count <= toiterate.max():
            for i in toiterate: 
                if i ==count:
                    newtime.append(newyears[count])
            count+=1
        print "Finished", str(chunknum), "chunks"
        chunk["time"] = newtime #create new column in dataframe based on time
        outname = "CHIRPS_tanz_time2.csv"
        #append each output to same csv, using no header
        chunk.to_csv(pathlist[2]+outname, mode='a', header=None, index=None)
timpjohns
sumber
9

Saya ingin menunjukkan paket Vaex.

Vaex adalah pustaka python untuk malas DataFrames Out-of-Core (mirip dengan Pandas), untuk memvisualisasikan dan mengeksplorasi dataset tabular besar. Ia dapat menghitung statistik seperti rata-rata, jumlah, jumlah, standar deviasi dll, pada grid N-dimensional hingga satu miliar (10 9 ) objek / baris per detik. Visualisasi dilakukan menggunakan histogram, plot kerapatan, dan rendering volume 3d, memungkinkan eksplorasi data besar secara interaktif. Vaex menggunakan pemetaan memori, kebijakan penyalinan nol memori, dan perhitungan malas untuk kinerja terbaik (tidak ada memori yang terbuang).

Lihat dokumentasi: https://vaex.readthedocs.io/en/latest/ API sangat dekat dengan API panda.

rampok
sumber
0

Mengapa panda? Sudahkah Anda mencoba Standard Python ?

Penggunaan python perpustakaan standar. Panda tunduk pada pembaruan yang sering, bahkan dengan rilis terbaru dari versi stabil.

Menggunakan pustaka python standar kode Anda akan selalu berjalan.

Salah satu cara melakukannya adalah memiliki gagasan tentang cara Anda ingin data Anda disimpan, dan pertanyaan mana yang ingin Anda selesaikan terkait data tersebut. Kemudian gambarkan skema bagaimana Anda bisa mengatur data Anda (think tables) yang akan membantu Anda meminta data, tidak harus normalisasi.

Anda dapat memanfaatkan:

  • daftar kamus untuk menyimpan data dalam memori, satu dict menjadi satu baris,
  • generator untuk memproses baris data demi baris agar tidak meluap RAM Anda,
  • daftar pemahaman untuk menanyakan data Anda,
  • memanfaatkan Counter, DefaultDict, ...
  • menyimpan data Anda di hard drive Anda menggunakan solusi penyimpanan apa pun yang telah Anda pilih, json bisa menjadi salah satunya.

Ram dan HDD menjadi lebih murah dan lebih murah dengan waktu dan standar python 3 tersedia secara luas dan stabil.

Pelikan
sumber
-1

Saat ini saya bekerja "seperti" Anda, hanya pada skala yang lebih rendah, itulah sebabnya saya tidak memiliki PoC untuk saran saya.

Namun, saya sepertinya menemukan sukses dalam menggunakan acar sebagai sistem caching dan outsourcing pelaksanaan berbagai fungsi ke dalam file - mengeksekusi file-file ini dari commando / file utama saya; Misalnya saya menggunakan prep_use.py untuk mengkonversi tipe objek, membagi set data menjadi tes, memvalidasi dan set data prediksi.

Bagaimana cara caching Anda dengan acar bekerja? Saya menggunakan string untuk mengakses file acar yang dibuat secara dinamis, tergantung pada parameter dan kumpulan data yang dilewati (dengan itu saya mencoba untuk menangkap dan menentukan apakah program sudah dijalankan, menggunakan .shape untuk set data, dict untuk disahkan parameter). Menghormati langkah-langkah ini, saya mendapatkan sebuah String untuk mencoba menemukan dan membaca file .pickle dan dapat, jika ditemukan, melewatkan waktu pemrosesan untuk melompat ke eksekusi yang sedang saya kerjakan sekarang.

Menggunakan database saya mengalami masalah yang sama, itulah sebabnya saya menemukan sukacita dalam menggunakan solusi ini, namun - ada banyak kendala pasti - misalnya menyimpan set acar besar karena redundansi. Memperbarui tabel dari sebelum ke setelah transformasi dapat dilakukan dengan pengindeksan yang tepat - memvalidasi informasi membuka seluruh buku lain (saya mencoba mengkonsolidasikan data sewaan merangkak dan berhenti menggunakan database setelah 2 jam pada dasarnya - karena saya ingin melompat kembali setelah setiap proses transformasi)

Saya harap 2 sen saya membantu Anda dalam beberapa cara.

Salam pembuka.

TiRoX
sumber