Bagaimana cara mengulangi baris dalam DataFrame di Pandas?

1954

Saya punya DataFramedari panda:

import pandas as pd
inp = [{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}]
df = pd.DataFrame(inp)
print df

Keluaran:

   c1   c2
0  10  100
1  11  110
2  12  120

Sekarang saya ingin beralih di barisan frame ini. Untuk setiap baris saya ingin dapat mengakses elemen-elemennya (nilai dalam sel) dengan nama kolom. Sebagai contoh:

for row in df.rows:
   print row['c1'], row['c2']

Mungkinkah melakukannya di panda?

Saya menemukan pertanyaan serupa ini . Tetapi itu tidak memberi saya jawaban yang saya butuhkan. Misalnya, disarankan untuk menggunakan:

for date, row in df.T.iteritems():

atau

for row in df.iterrows():

Tapi saya tidak mengerti apa rowobjeknya dan bagaimana saya bisa bekerja dengannya.

Roma
sumber
11
The df.iteritems () berulang di atas kolom dan bukan baris. Jadi, untuk membuatnya berulang di atas baris, Anda harus mengubah posisi ("T"), yang berarti Anda mengubah baris dan kolom menjadi satu sama lain (mencerminkan lebih dari diagonal). Akibatnya, Anda secara efektif mengulang bingkai data asli di atas barisnya saat Anda menggunakan df.T.iteritems ()
Stefan Gruenwald
12
Jika Anda baru di utas ini dan merupakan pemula untuk panda, JANGAN ITERASI !! Iterasi atas dataframe adalah anti-pola, dan sesuatu yang tidak boleh Anda lakukan kecuali jika Anda ingin terbiasa dengan banyak menunggu. Tergantung pada apa yang Anda coba lakukan, mungkin ada alternatif yang jauh lebih baik . iter*fungsi harus digunakan dalam keadaan yang sangat jarang. Juga terkait .
cs95
19
Berbeda dengan apa yang dikatakan cs95, ada alasan bagus untuk ingin mengulangi dataframe, jadi pengguna baru seharusnya tidak merasa kecil hati. Salah satu contoh adalah jika Anda ingin menjalankan beberapa kode menggunakan nilai dari setiap baris sebagai input. Juga, jika kerangka data Anda cukup kecil (mis. Kurang dari 1000 item), kinerja tidak benar-benar masalah.
oulenz
1
@oulenz: Jika karena alasan aneh Anda ingin terbang saat menggunakan API untuk tujuan dirancangnya (transformasi data berkinerja tinggi), maka jadilah tamu saya. Tapi paling tidak, jangan gunakan iterrows, ada cara yang lebih baik untuk mengulangi DataFrame, Anda mungkin juga hanya mengulang daftar daftar pada saat itu. Jika Anda berada pada titik di mana Anda tidak melakukan apa-apa selain melakukan iterasi pada DataFrames, tidak ada manfaat sama sekali untuk menggunakan DataFrame sama sekali (dengan asumsi iterasi di atasnya adalah satu-satunya hal yang Anda lakukan dengannya). Hanya 2c saya.
cs95
8
Saya kedua @oulenz. Sejauh yang saya tahu pandasadalah pilihan masuk untuk membaca file csv bahkan jika dataset kecil. Ini hanya pemrograman yang lebih mudah untuk memanipulasi data dengan API
Chris

Jawaban:

2640

DataFrame.iterrows adalah generator yang menghasilkan indeks dan baris

import pandas as pd
import numpy as np

df = pd.DataFrame([{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}])

for index, row in df.iterrows():
    print(row['c1'], row['c2'])

Output: 
   10 100
   11 110
   12 120
waitingkuo
sumber
207
Catatan: "Karena iterrows mengembalikan Seri untuk setiap baris, itu tidak mempertahankan dtypes di baris." Juga, "Anda seharusnya tidak pernah memodifikasi sesuatu yang Anda iterasi." Menurut panda 0.19.1 dokumen
viddik13
3
@ viddik13 itu catatan yang bagus terima kasih. Karena itu saya mengalami kasus di mana nilai numerik seperti di 431341610650mana dibaca sebagai 4.31E+11. Apakah ada cara untuk melestarikan dtypes?
Aziz Alto
26
@AzizAlto digunakan itertuples, seperti yang dijelaskan di bawah ini. Lihat juga pandas.pydata.org/pandas-docs/stable/generated/…
Axel
101
Jangan gunakan iterrows. Itertuples lebih cepat dan mempertahankan tipe data. Info lebih lanjut
James L.
11
Dari dokumentasi : "Iterasi melalui objek panda umumnya lambat. Dalam banyak kasus, iterasi secara manual pada baris tidak diperlukan [...]". Jawaban Anda benar (dalam konteks pertanyaan) tetapi tidak menyebutkannya di mana pun, jadi jawabannya tidak terlalu bagus.
cs95
464

Bagaimana cara mengulangi baris dalam DataFrame di Pandas?

Jawab: JANGAN * !

Iterasi dalam panda adalah anti-pola, dan merupakan sesuatu yang harus Anda lakukan hanya jika Anda telah kehabisan setiap opsi lainnya. Anda tidak boleh menggunakan fungsi apa pun dengan " iter" namanya lebih dari beberapa ribu baris atau Anda harus terbiasa dengan banyak menunggu.

Apakah Anda ingin mencetak DataFrame? Gunakan DataFrame.to_string().

Apakah Anda ingin menghitung sesuatu? Dalam hal ini, cari metode dalam urutan ini (daftar dimodifikasi dari sini ):

  1. Vektorisasi
  2. Rutinitas cython
  3. Daftar Pemahaman (vanilla forloop)
  4. DataFrame.apply(): i) Pengurangan yang dapat dilakukan dalam cython, ii) Iterasi dalam ruang python
  5. DataFrame.itertuples() dan iteritems()
  6. DataFrame.iterrows()

iterrowsdan itertuples(keduanya menerima banyak suara sebagai jawaban atas pertanyaan ini) harus digunakan dalam keadaan yang sangat jarang, seperti menghasilkan objek baris / nametuple untuk pemrosesan sekuensial, yang merupakan satu-satunya hal yang berguna untuk fungsi-fungsi ini.

Banding ke Otoritas
Halaman dokumen tentang pengulangan memiliki kotak peringatan merah besar yang bertuliskan:

Iterasi melalui objek panda umumnya lambat. Dalam banyak kasus, iterasi secara manual di atas baris tidak diperlukan [...].

* Ini sebenarnya sedikit lebih rumit daripada "jangan". df.iterrows()adalah jawaban yang benar untuk pertanyaan ini, tetapi "vectorize your ops" adalah yang lebih baik. Saya akan mengakui bahwa ada keadaan di mana iterasi tidak dapat dihindari (misalnya, beberapa operasi di mana hasilnya tergantung pada nilai yang dihitung untuk baris sebelumnya). Namun, perlu beberapa keakraban dengan perpustakaan untuk mengetahui kapan. Jika Anda tidak yakin apakah Anda membutuhkan solusi berulang, Anda mungkin tidak. PS: Untuk mengetahui lebih banyak tentang pemikiran saya untuk menulis jawaban ini, lompat ke bagian paling bawah.


Lebih cepat dari Looping: Vektorisasi , Cython

Sejumlah operasi dasar dan komputasi yang baik "di-vektor-kan" oleh panda (baik melalui NumPy, atau melalui fungsi-fungsi Cythonized). Ini termasuk aritmatika, perbandingan, pengurangan (sebagian besar), pembentukan kembali (seperti berputar), bergabung, dan operasi grup oleh. Lihat dokumentasi tentang Fungsi Dasar Esensial untuk menemukan metode vektorised yang cocok untuk masalah Anda.

Jika tidak ada, jangan ragu untuk menulis sendiri menggunakan ekstensi cython khusus .


Hal Terbaik Berikutnya: Daftar Pemahaman *

Pemahaman daftar harus menjadi porta panggilan Anda berikutnya jika 1) tidak ada solusi vektorisasi yang tersedia, 2) kinerja penting, tetapi tidak cukup penting untuk melewati kerumitan cythonisasi kode Anda, dan 3) Anda mencoba melakukan transformasi elementwise pada kode Anda. Ada sejumlah bukti yang baik untuk menunjukkan bahwa pemahaman daftar cukup cepat (dan bahkan terkadang lebih cepat) untuk banyak tugas panda umum.

Rumusnya sederhana,

# iterating over one column - `f` is some function that processes your data
result = [f(x) for x in df['col']]
# iterating over two columns, use `zip`
result = [f(x, y) for x, y in zip(df['col1'], df['col2'])]
# iterating over multiple columns - same data type
result = [f(row[0], ..., row[n]) for row in df[['col1', ...,'coln']].to_numpy()]
# iterating over multiple columns - differing data type
result = [f(row[0], ..., row[n]) for row in zip(df['col1'], ..., df['coln'])]

Jika Anda bisa merangkum logika bisnis Anda ke dalam suatu fungsi, Anda bisa menggunakan pemahaman daftar yang menyebutnya. Anda dapat membuat hal-hal rumit yang semena-mena bekerja melalui kesederhanaan dan kecepatan python mentah.


Pemahaman Caveats List menganggap bahwa data Anda mudah dikerjakan - artinya adalah tipe data Anda konsisten dan Anda tidak memiliki NaN, tetapi ini tidak selalu dapat dijamin.

  1. Yang pertama lebih jelas, tetapi ketika berhadapan dengan NaN, lebih memilih metode panda built-in jika ada (karena mereka memiliki logika penanganan kasus sudut jauh lebih baik), atau memastikan logika bisnis Anda menyertakan logika penanganan NaN yang sesuai.
  2. Saat berurusan dengan tipe data campuran, Anda harus mengulanginya alih- zip(df['A'], df['B'], ...)alih df[['A', 'B']].to_numpy()karena yang terakhir secara implisit mengirimkan data ke tipe yang paling umum. Sebagai contoh jika A adalah numerik dan B adalah string, to_numpy()akan melemparkan seluruh array ke string, yang mungkin bukan yang Anda inginkan. Untungnya zipping kolom Anda bersama adalah solusi paling mudah untuk ini.

* YMMV untuk alasan yang diuraikan di bagian Peringatan di atas.


Contoh yang Jelas

Mari kita tunjukkan perbedaannya dengan contoh sederhana menambahkan dua kolom panda A + B. Ini adalah operasi vektorizable, sehingga akan mudah untuk membandingkan kinerja metode yang dibahas di atas.

masukkan deskripsi gambar di sini

Kode benchmark, untuk referensi Anda.

Saya harus menyebutkan, bahwa tidak selalu luka dan kering seperti ini. Terkadang jawaban untuk "apa metode terbaik untuk operasi" adalah "itu tergantung pada data Anda". Saran saya adalah untuk menguji berbagai pendekatan pada data Anda sebelum memutuskannya.


Bacaan lebih lanjut

* Metode string panda adalah "vektor" dalam arti bahwa mereka ditentukan pada seri tetapi beroperasi pada setiap elemen. Mekanisme yang mendasarinya masih berulang, karena operasi string secara inheren sulit untuk di-vektorisasi.


Mengapa Saya Menulis Jawaban ini

Tren umum yang saya perhatikan dari pengguna baru adalah untuk mengajukan pertanyaan dari formulir "bagaimana saya bisa beralih ke df saya untuk melakukan X?". Menampilkan kode yang memanggil iterrows()saat melakukan sesuatu di dalam for loop. Inilah sebabnya. Seorang pengguna baru ke perpustakaan yang belum diperkenalkan dengan konsep vektorisasi kemungkinan akan membayangkan kode yang memecahkan masalah mereka saat iterasi data mereka untuk melakukan sesuatu. Tidak tahu bagaimana cara mengulang melalui DataFrame, hal pertama yang mereka lakukan adalah Google dan berakhir di sini, pada pertanyaan ini. Mereka kemudian melihat jawaban yang diterima memberitahu mereka bagaimana caranya, dan mereka menutup mata mereka dan menjalankan kode ini tanpa terlebih dahulu mempertanyakan apakah iterasi bukan hal yang benar untuk dilakukan.

Tujuan dari jawaban ini adalah untuk membantu pengguna baru memahami bahwa iterasi tidak selalu merupakan solusi untuk setiap masalah, dan bahwa solusi yang lebih baik, lebih cepat, dan lebih idiomatik dapat ada, dan bahwa ada baiknya menginvestasikan waktu untuk menjelajahi mereka. Saya tidak mencoba untuk memulai perang iterasi vs vektorisasi, tapi saya ingin pengguna baru diberi tahu ketika mengembangkan solusi untuk masalah mereka dengan perpustakaan ini.

cs95
sumber
24
Ini adalah satu-satunya jawaban yang berfokus pada teknik idiomatik yang harus digunakan dengan panda, menjadikannya jawaban terbaik untuk pertanyaan ini. Belajar mendapatkan jawaban yang benar dengan kode yang benar (alih-alih jawaban yang benar dengan kode yang salah - yaitu tidak efisien, tidak berskala, terlalu cocok dengan data tertentu) adalah bagian besar dari pembelajaran panda (dan data pada umumnya).
LinkBerest
3
Saya pikir Anda tidak adil untuk loop, meskipun, karena mereka hanya sedikit lebih lambat dari daftar pemahaman dalam tes saya. Triknya adalah untuk mengulang alih- zip(df['A'], df['B'])alih df.iterrows().
Imperishable Night
2
@ImperishableNight Tidak sama sekali; maksud dari posting ini bukan untuk mengecam iterasi secara umum - itu adalah untuk secara khusus mengecam penggunaan iterrows(), dan secara implisit mencela iterasi jika dan ketika ada alternatif yang lebih baik. forloop sendiri tidak masalah, tetapi daftar pemahaman lebih baik jika Anda melakukan transformasi elemen-iter.
cs95
1
@ sdbbs, gunakan sort_values ​​untuk mengurutkan data Anda, lalu panggil to_string () pada hasilnya.
cs95
1
Di bawah Daftar Pemahaman, contoh "pengulangan lebih dari beberapa kolom" memerlukan peringatan: DataFrame.valuesakan mengonversi setiap kolom ke tipe data umum. DataFrame.to_numpy()melakukan ini juga. Untungnya kita dapat menggunakan zipsejumlah kolom.
David Wasserman
397

Pertama-tama pertimbangkan apakah Anda benar-benar harus mengulangi baris dalam DataFrame. Lihat jawaban ini untuk alternatif.

Jika Anda masih perlu melakukan iterate pada baris, Anda dapat menggunakan metode di bawah ini. Perhatikan beberapa peringatan penting yang tidak disebutkan dalam jawaban lainnya.

itertuples() seharusnya lebih cepat dari iterrows()

Tetapi berhati-hatilah, menurut dokumen (panda 0.24.2 saat ini):

  • iterrows: dtypemungkin tidak cocok dari baris ke baris

    Karena iterrows mengembalikan Seri untuk setiap baris, itu tidak mempertahankan dtypes di baris (dtypes disimpan di kolom untuk DataFrames). Untuk mempertahankan dtypes saat iterasi di atas baris, lebih baik menggunakan ittuple () yang mengembalikan nama nilai-nilai dan yang umumnya jauh lebih cepat daripada iterrows ()

  • iterrows: Jangan memodifikasi baris

    Anda seharusnya tidak pernah memodifikasi sesuatu yang Anda ulangi. Ini tidak dijamin berfungsi dalam semua kasus. Bergantung pada tipe data, iterator mengembalikan salinan dan bukan tampilan, dan menulis ke sana tidak akan berpengaruh.

    Gunakan DataFrame.apply () sebagai gantinya:

    new_df = df.apply(lambda x: x * 2)
  • itertuples:

    Nama kolom akan diubah namanya menjadi nama posisional jika mereka pengidentifikasi Python tidak valid, diulang, atau mulai dengan garis bawah. Dengan sejumlah besar kolom (> 255), tupel biasa dikembalikan.

Lihat panda docs pada iterasi untuk lebih jelasnya.

viddik13
sumber
4
Hanya pertanyaan kecil dari seseorang yang membaca utas ini begitu lama setelah selesai: bagaimana df.apply () dibandingkan dengan itertuple dalam hal efisiensi?
Raul Guarini
4
Catatan: Anda juga bisa mengatakan sesuatu seperti for row in df[['c1','c2']].itertuples(index=True, name=None):hanya menyertakan kolom tertentu di iterator baris.
Brian Burns
12
Alih-alih getattr(row, "c1"), Anda bisa menggunakan adil row.c1.
viraptor
1
Saya sekitar 90% yakin bahwa jika Anda menggunakan getattr(row, "c1")alih-alih row.c1, Anda kehilangan keunggulan kinerja apa pun itertuples, dan jika Anda benar-benar perlu pergi ke properti melalui string, Anda harus menggunakannya sebagai gantinya.
Noctiphobia
3
Saya telah menemukan pertanyaan ini karena, meskipun saya tahu ada split-apply-menggabungkan, saya masih benar-benar perlu untuk beralih ke DataFrame (seperti yang dinyatakan dalam pertanyaan). Tidak semua orang memiliki kemewahan untuk ditingkatkan dengan numbadan cython(dokumen yang sama mengatakan bahwa "Selalu layak dioptimalkan dengan Python pertama"). Saya menulis jawaban ini untuk membantu orang lain menghindari (terkadang membuat frustrasi) masalah karena tidak ada jawaban lain yang menyebutkan peringatan ini. Menyesatkan siapa pun atau mengatakan "itu hal yang benar untuk dilakukan" bukanlah niat saya. Saya telah memperbaiki jawabannya.
viddik13
201

Anda harus menggunakan df.iterrows(). Meskipun iterasi baris demi baris tidak terlalu efisien karena Seriesobjek harus dibuat.

Wes McKinney
sumber
12
Apakah ini lebih cepat daripada mengonversi DataFrame ke array numpy (via .values) dan beroperasi pada array secara langsung? Saya memiliki masalah yang sama, tetapi akhirnya mengkonversi ke array numpy dan kemudian menggunakan cython.
vgoklani
12
@vgoklani Jika iterasi baris demi baris tidak efisien dan Anda memiliki array numpy non-objek maka hampir pasti menggunakan array numpy mentah akan lebih cepat, terutama untuk array dengan banyak baris. Anda harus menghindari iterasi pada baris kecuali Anda benar-benar harus
Phillip Cloud
7
Saya telah melakukan sedikit pengujian pada konsumsi waktu untuk df.iterrows (), df.itertuples (), dan zip (df ['a'], df ['b']) dan memposting hasilnya dalam jawaban yang lain pertanyaan: stackoverflow.com/a/34311080/2142098
Richard Wong
154

Meskipun iterrows()merupakan pilihan yang baik, terkadang itertuples()bisa jauh lebih cepat:

df = pd.DataFrame({'a': randn(1000), 'b': randn(1000),'N': randint(100, 1000, (1000)), 'x': 'x'})

%timeit [row.a * 2 for idx, row in df.iterrows()]
# => 10 loops, best of 3: 50.3 ms per loop

%timeit [row[1] * 2 for row in df.itertuples()]
# => 1000 loops, best of 3: 541 µs per loop
e9t
sumber
5
Sebagian besar perbedaan waktu dalam dua contoh Anda sepertinya disebabkan oleh fakta bahwa Anda tampaknya menggunakan pengindeksan berbasis label untuk perintah .iterrows () dan pengindeksan berbasis integer untuk perintah .itertuples ().
Alex
2
Untuk dataframe berbasis data keuangan (timestamp, dan 4x float), itu meningkat 19,57 kali lebih cepat daripada itu di mesin saya. Hanya for a,b,c in izip(df["a"],df["b"],df["c"]:hampir sama cepatnya.
harbun
7
Bisakah Anda jelaskan mengapa lebih cepat?
Abe Miessler
4
@AbeMiessler mengemas iterrows()setiap baris data ke dalam Seri, sedangkan itertuples()tidak.
miradulo
3
Perhatikan bahwa urutan kolom sebenarnya tidak pasti, karena dfdibuat dari kamus, jadi row[1]bisa merujuk ke salah satu kolom. Ternyata meskipun waktunya kira-kira sama untuk bilangan bulat vs kolom float.
Brian Burns
88

Anda juga dapat menggunakannya df.apply()untuk beralih pada baris dan mengakses beberapa kolom untuk suatu fungsi.

docs: DataFrame.apply ()

def valuation_formula(x, y):
    return x * y * 0.5

df['price'] = df.apply(lambda row: valuation_formula(row['x'], row['y']), axis=1)
cheekybastard
sumber
Apakah df ['harga'] merujuk pada nama kolom dalam bingkai data? Saya mencoba membuat kamus dengan nilai unik dari beberapa kolom dalam file csv. Saya menggunakan logika Anda untuk membuat kamus dengan kunci dan nilai unik dan mendapat kesalahan yang menyatakan bahwa TypeError: ("Objek 'Seri' dapat diubah, sehingga tidak dapat di-hash", Anda tidak ditemukan di indeks 0 ')
SRS
Kode: df ['Workclass'] = df.apply (baris lambda: dic_update (baris), axis = 1) akhir baris id = 0 akhir baris def dic_update (baris): jika baris tidak dalam dic: dic [baris] = id id = id + 1
SRS
Sudahlah, saya mengerti. Mengubah saluran panggilan fungsi menjadi df_new = df ['Workclass']. Berlaku (hal yang sama)
SRS
2
Memiliki sumbu bawaan ke 0 adalah yang terburuk
zthomas.nc
9
Perhatikan bahwa applytidak "iteratite" di atas baris, melainkan menerapkan fungsi baris-bijaksana. Kode di atas tidak akan berfungsi jika Anda benar - benar membutuhkan iterasi dan indeces, misalnya ketika membandingkan nilai di berbagai baris (dalam hal ini Anda tidak dapat melakukan apa pun selain iterasi).
gented
82

Anda dapat menggunakan fungsi df.iloc sebagai berikut:

for i in range(0, len(df)):
    print df.iloc[i]['c1'], df.iloc[i]['c2']
PJay
sumber
1
Saya tahu bahwa seseorang harus menghindari ini demi iterrows atau itupuple, tetapi akan menarik untuk mengetahui mengapa. Adakah pikiran?
rocarvaj
12
Ini adalah satu-satunya teknik valid yang saya tahu jika Anda ingin mempertahankan tipe data, dan juga merujuk ke kolom dengan nama. itertuplesmempertahankan tipe data, tetapi menyingkirkan nama apa pun yang tidak disukainya. iterrowsmelakukan yang sebaliknya.
Ken Williams
6
Menghabiskan berjam-jam mencoba mengarungi keanehan struktur data panda untuk melakukan sesuatu yang sederhana DAN ekspresif. Ini menghasilkan kode yang dapat dibaca.
Sean Anderson
Meskipun for i in range(df.shape[0])mungkin mempercepat pendekatan ini sedikit, masih sekitar 3,5x lebih lambat daripada pendekatan iterrows () di atas untuk aplikasi saya.
Kim Miller
Pada Datafrmes besar ini tampaknya lebih baik karena my_iter = df.itertuples()membutuhkan memori dua kali lipat dan banyak waktu untuk menyalinnya. sama untuk iterrows().
Bastiaan
33

Saya sedang mencari Bagaimana cara mengulang pada baris DAN kolom dan berakhir di sini jadi:

for i, row in df.iterrows():
    for j, column in row.iteritems():
        print(column)
Lucas B
sumber
18

Anda dapat menulis iterator Anda sendiri yang mengimplementasikan namedtuple

from collections import namedtuple

def myiter(d, cols=None):
    if cols is None:
        v = d.values.tolist()
        cols = d.columns.values.tolist()
    else:
        j = [d.columns.get_loc(c) for c in cols]
        v = d.values[:, j].tolist()

    n = namedtuple('MyTuple', cols)

    for line in iter(v):
        yield n(*line)

Ini secara langsung sebanding dengan pd.DataFrame.itertuples. Saya bertujuan melakukan tugas yang sama dengan lebih efisien.


Untuk kerangka data yang diberikan dengan fungsi saya:

list(myiter(df))

[MyTuple(c1=10, c2=100), MyTuple(c1=11, c2=110), MyTuple(c1=12, c2=120)]

Atau dengan pd.DataFrame.itertuples:

list(df.itertuples(index=False))

[Pandas(c1=10, c2=100), Pandas(c1=11, c2=110), Pandas(c1=12, c2=120)]

Tes komprehensif
Kami menguji membuat semua kolom tersedia dan mengatur ulang kolom.

def iterfullA(d):
    return list(myiter(d))

def iterfullB(d):
    return list(d.itertuples(index=False))

def itersubA(d):
    return list(myiter(d, ['col3', 'col4', 'col5', 'col6', 'col7']))

def itersubB(d):
    return list(d[['col3', 'col4', 'col5', 'col6', 'col7']].itertuples(index=False))

res = pd.DataFrame(
    index=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
    columns='iterfullA iterfullB itersubA itersubB'.split(),
    dtype=float
)

for i in res.index:
    d = pd.DataFrame(np.random.randint(10, size=(i, 10))).add_prefix('col')
    for j in res.columns:
        stmt = '{}(d)'.format(j)
        setp = 'from __main__ import d, {}'.format(j)
        res.at[i, j] = timeit(stmt, setp, number=100)

res.groupby(res.columns.str[4:-1], axis=1).plot(loglog=True);

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

piRquared
sumber
2
Bagi orang yang tidak ingin membaca kode: garis biru intertuples, garis oranye adalah daftar iterator melalui blok hasil. interrowstidak dibandingkan.
James L.
18

Bagaimana cara iterate secara efisien?

Jika Anda benar-benar harus mengulang bingkai data panda, Anda mungkin ingin menghindari menggunakan iterrows () . Ada berbagai metode dan biasanya iterrows()jauh dari yang terbaik. itertuples () bisa 100 kali lebih cepat.

Pendeknya:

  • Sebagai aturan umum, gunakan df.itertuples(name=None). Khususnya, ketika Anda memiliki kolom angka tetap dan kurang dari 255 kolom. Lihat poin (3)
  • Kalau tidak, gunakan df.itertuples()kecuali jika kolom Anda memiliki karakter khusus seperti spasi atau '-'. Lihat poin (2)
  • Dimungkinkan untuk menggunakan itertuples()bahkan jika kerangka data Anda memiliki kolom aneh dengan menggunakan contoh terakhir. Lihat poin (4)
  • Hanya gunakan iterrows()jika Anda tidak dapat solusi sebelumnya. Lihat poin (1)

Metode berbeda untuk beralih pada baris dalam bingkai data panda:

Hasilkan kerangka data acak dengan sejuta baris dan 4 kolom:

    df = pd.DataFrame(np.random.randint(0, 100, size=(1000000, 4)), columns=list('ABCD'))
    print(df)

1) Biasanya iterrows()nyaman tetapi sangat lambat:

start_time = time.clock()
result = 0
for _, row in df.iterrows():
    result += max(row['B'], row['C'])

total_elapsed_time = round(time.clock() - start_time, 2)
print("1. Iterrows done in {} seconds, result = {}".format(total_elapsed_time, result))

2) Default itertuples()sudah jauh lebih cepat tetapi tidak bekerja dengan nama kolom seperti My Col-Name is very Strange(Anda harus menghindari metode ini jika kolom Anda diulangi atau jika nama kolom tidak dapat dengan mudah dikonversi ke nama variabel python) .:

start_time = time.clock()
result = 0
for row in df.itertuples(index=False):
    result += max(row.B, row.C)

total_elapsed_time = round(time.clock() - start_time, 2)
print("2. Named Itertuples done in {} seconds, result = {}".format(total_elapsed_time, result))

3) Default itertuples()menggunakan nama = Tidak ada bahkan lebih cepat tetapi tidak benar-benar nyaman karena Anda harus mendefinisikan variabel per kolom.

start_time = time.clock()
result = 0
for(_, col1, col2, col3, col4) in df.itertuples(name=None):
    result += max(col2, col3)

total_elapsed_time = round(time.clock() - start_time, 2)
print("3. Itertuples done in {} seconds, result = {}".format(total_elapsed_time, result))

4) Akhirnya, nama itertuples()lebih lambat dari titik sebelumnya tetapi Anda tidak perlu mendefinisikan variabel per kolom dan itu bekerja dengan nama-nama kolom seperti My Col-Name is very Strange.

start_time = time.clock()
result = 0
for row in df.itertuples(index=False):
    result += max(row[df.columns.get_loc('B')], row[df.columns.get_loc('C')])

total_elapsed_time = round(time.clock() - start_time, 2)
print("4. Polyvalent Itertuples working even with special characters in the column name done in {} seconds, result = {}".format(total_elapsed_time, result))

Keluaran:

         A   B   C   D
0       41  63  42  23
1       54   9  24  65
2       15  34  10   9
3       39  94  82  97
4        4  88  79  54
...     ..  ..  ..  ..
999995  48  27   4  25
999996  16  51  34  28
999997   1  39  61  14
999998  66  51  27  70
999999  51  53  47  99

[1000000 rows x 4 columns]

1. Iterrows done in 104.96 seconds, result = 66151519
2. Named Itertuples done in 1.26 seconds, result = 66151519
3. Itertuples done in 0.94 seconds, result = 66151519
4. Polyvalent Itertuples working even with special characters in the column name done in 2.94 seconds, result = 66151519

Artikel ini adalah perbandingan yang sangat menarik antara iterrows dan itupuples

Capron Romain
sumber
14

Untuk mengulang semua baris dalam, dataframeAnda dapat menggunakan:

for x in range(len(date_example.index)):
    print date_example['Date'].iloc[x]
CONvid19
sumber
1
Ini adalah pengindeksan berantai. Saya tidak merekomendasikan melakukan ini.
cs95
@ cs95 Apa yang akan Anda rekomendasikan?
CONvid19
Jika Anda ingin membuat ini berfungsi, panggil df.columns.get_loc untuk mendapatkan posisi indeks integer dari kolom tanggal (di luar loop), kemudian gunakan panggilan pengindeksan iloc tunggal di dalam.
cs95
14
 for ind in df.index:
     print df['c1'][ind], df['c2'][ind]
Grag2015
sumber
1
bagaimana kinerja opsi ini bila digunakan pada kerangka data yang besar (misalnya jutaan baris)?
Bazyli Debowski
Jujur, saya tidak tahu persis, saya pikir bahwa dibandingkan dengan jawaban terbaik, waktu yang telah berlalu akan hampir sama, karena kedua kasus menggunakan "untuk" konstruksi. Tetapi memori mungkin berbeda dalam beberapa kasus.
Grag2015
4
Ini adalah pengindeksan berantai. Jangan gunakan ini!
cs95
7

Terkadang pola yang bermanfaat adalah:

# Borrowing @KutalmisB df example
df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]}, index=['a', 'b'])
# The to_dict call results in a list of dicts
# where each row_dict is a dictionary with k:v pairs of columns:value for that row
for row_dict in df.to_dict(orient='records'):
    print(row_dict)

Yang mengakibatkan:

{'col1':1.0, 'col2':0.1}
{'col1':2.0, 'col2':0.2}
Zach
sumber
6

Untuk mengulang semua baris dalam dataframedan menggunakan nilai setiap baris dengan mudah , namedtuplesdapat dikonversi ke ndarrays. Sebagai contoh:

df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]}, index=['a', 'b'])

Iterasi di atas baris:

for row in df.itertuples(index=False, name='Pandas'):
    print np.asarray(row)

menghasilkan:

[ 1.   0.1]
[ 2.   0.2]

Harap dicatat bahwa jika index=True, indeks ditambahkan sebagai elemen pertama dari tuple , yang mungkin tidak diinginkan untuk beberapa aplikasi.

Insinyur Gratis Herpes
sumber
5

Ada cara untuk beralih baris melempar sambil mendapatkan DataFrame sebagai imbalan, dan bukan Seri. Saya tidak melihat ada orang yang menyebutkan bahwa Anda dapat melewati indeks sebagai daftar untuk baris yang akan dikembalikan sebagai DataFrame:

for i in range(len(df)):
    row = df.iloc[[i]]

Perhatikan penggunaan kurung ganda. Ini mengembalikan DataFrame dengan satu baris.

Zeitgeist
sumber
Ini sangat membantu untuk mendapatkan baris ke-n terbesar dalam bingkai data setelah pengurutan. Terima kasih!
Jason Harrison
3

Untuk melihat dan memodifikasi nilai, saya akan menggunakan iterrows(). Dalam untuk loop dan dengan menggunakan tuple membongkar (lihat contoh: i, row), saya menggunakan rowhanya melihat nilai dan penggunaan idengan locmetode ketika saya ingin memodifikasi nilai-nilai. Seperti yang dinyatakan dalam jawaban sebelumnya, di sini Anda tidak boleh mengubah sesuatu yang Anda iterasi.

for i, row in df.iterrows():
    df_column_A = df.loc[i, 'A']
    if df_column_A == 'Old_Value':
        df_column_A = 'New_value'  

Di sini, rowdi loop adalah salinan dari baris itu, dan bukan tampilan itu. Karena itu, Anda TIDAK boleh menulis sesuatu seperti row['A'] = 'New_Value', itu tidak akan mengubah DataFrame. Namun, Anda dapat menggunakan idan locdan menentukan DataFrame untuk melakukan pekerjaan.

Hossein
sumber
2

Saya tahu saya terlambat ke pesta penjawab, tapi saya hanya ingin menambahkan jawaban @ cs95 di atas, yang saya percaya harus menjadi jawaban yang diterima. Dalam jawabannya, ia menunjukkan bahwa vektorisasi panda jauh lebih baik dari metode panda lain untuk menghitung barang dengan kerangka data.

Saya ingin menambahkan bahwa jika Anda pertama kali mengkonversi dataframe ke array numpy dan kemudian menggunakan vektorisasi, itu bahkan lebih cepat daripada pandas dataframe vectorization, (dan itu termasuk waktu untuk mengubahnya kembali menjadi seri dataframe).

Jika Anda menambahkan fungsi berikut ke kode benchmark @ cs95, ini menjadi sangat jelas:

def np_vectorization(df):
    np_arr = df.to_numpy()
    return pd.Series(np_arr[:,0] + np_arr[:,1], index=df.index)

def just_np_vectorization(df):
    np_arr = df.to_numpy()
    return np_arr[:,0] + np_arr[:,1]

masukkan deskripsi gambar di sini

semprotan serangga
sumber
1

Anda juga dapat melakukan numpypengindeksan untuk peningkatan kecepatan yang lebih besar. Ini tidak benar-benar iterasi tetapi bekerja jauh lebih baik daripada iterasi untuk aplikasi tertentu.

subset = row['c1'][0:5]
all = row['c1'][:]

Anda mungkin juga ingin melemparkannya ke sebuah array. Indeks / seleksi ini seharusnya bertindak seperti array Numpy tapi saya mengalami masalah dan perlu dilemparkan

np.asarray(all)
imgs[:] = cv2.resize(imgs[:], (224,224) ) #resize every image in an hdf5 file
James L.
sumber
1

Ada begitu banyak cara untuk beralih pada baris dalam bingkai data panda. Salah satu cara yang sangat sederhana dan intuitif adalah:

df=pd.DataFrame({'A':[1,2,3], 'B':[4,5,6],'C':[7,8,9]})
print(df)
for i in range(df.shape[0]):
    # For printing the second column
    print(df.iloc[i,1])
    # For printing more than one columns
    print(df.iloc[i,[0,2]])
shubham ranjan
sumber
0

Contoh ini menggunakan iloc untuk mengisolasi setiap digit dalam bingkai data.

import pandas as pd

 a = [1, 2, 3, 4]
 b = [5, 6, 7, 8]

 mjr = pd.DataFrame({'a':a, 'b':b})

 size = mjr.shape

 for i in range(size[0]):
     for j in range(size[1]):
         print(mjr.iloc[i, j])
mjr2000
sumber
0

Beberapa pustaka (mis. Pustaka interop Java yang saya gunakan) memerlukan nilai yang harus dilewati secara berurutan, misalnya, jika mengalirkan data. Untuk meniru sifat streaming, saya 'stream' nilai-nilai dataframe saya satu per satu, saya menulis di bawah ini, yang berguna dari waktu ke waktu.

class DataFrameReader:
  def __init__(self, df):
    self._df = df
    self._row = None
    self._columns = df.columns.tolist()
    self.reset()
    self.row_index = 0

  def __getattr__(self, key):
    return self.__getitem__(key)

  def read(self) -> bool:
    self._row = next(self._iterator, None)
    self.row_index += 1
    return self._row is not None

  def columns(self):
    return self._columns

  def reset(self) -> None:
    self._iterator = self._df.itertuples()

  def get_index(self):
    return self._row[0]

  def index(self):
    return self._row[0]

  def to_dict(self, columns: List[str] = None):
    return self.row(columns=columns)

  def tolist(self, cols) -> List[object]:
    return [self.__getitem__(c) for c in cols]

  def row(self, columns: List[str] = None) -> Dict[str, object]:
    cols = set(self._columns if columns is None else columns)
    return {c : self.__getitem__(c) for c in self._columns if c in cols}

  def __getitem__(self, key) -> object:
    # the df index of the row is at index 0
    try:
        if type(key) is list:
            ix = [self._columns.index(key) + 1 for k in key]
        else:
            ix = self._columns.index(key) + 1
        return self._row[ix]
    except BaseException as e:
        return None

  def __next__(self) -> 'DataFrameReader':
    if self.read():
        return self
    else:
        raise StopIteration

  def __iter__(self) -> 'DataFrameReader':
    return self

Yang bisa digunakan:

for row in DataFrameReader(df):
  print(row.my_column_name)
  print(row.to_dict())
  print(row['my_column_name'])
  print(row.tolist())

Dan mempertahankan pemetaan nilai / nama untuk baris yang diulang. Jelas, ini jauh lebih lambat daripada menggunakan apply dan Cython seperti yang ditunjukkan di atas, tetapi diperlukan dalam beberapa keadaan.

morganics
sumber
0

Pendeknya

  • Gunakan vektorisasi jika memungkinkan
  • Jika operasi tidak dapat di-vektorisasi - gunakan daftar pemahaman
  • Jika Anda membutuhkan objek tunggal yang mewakili seluruh baris - gunakan itertuples
  • Jika hal di atas terlalu lambat - coba swifter.apply
  • Jika masih terlalu lambat - coba Cython rutin

Detail dalam video ini

Tolok ukur Tolok ukur iterasi di atas baris dalam panda DataFrame

artoby
sumber