[:] Ve iloc [:] ile atamak pandalarda neden farklı sonuçlar veriyor?


13

ilocPandalarda kullanılan farklı indeksleme yöntemleri ile çok karıştım.

Diyelim ki bir 1-d Dataframe'i 2-d Dataframe'e dönüştürmeye çalışıyorum. İlk olarak aşağıdaki 1-D Dataframe var

a_array = [1,2,3,4,5,6,7,8]
a_df = pd.DataFrame(a_array).T

Ve bunu 2 boyutlu bir Dataframe'e dönüştüreceğim 2x4. 2-boyutlu Dataframe'i aşağıdaki gibi hazırlayarak başlıyorum:

b_df = pd.DataFrame(columns=range(4),index=range(2))

Daha sonra for-loop'u a_df(1-d) 'i b_df(2-d)' ye aşağıdaki kodla dönüştürmeme yardımcı olmak için kullanıyorum

for i in range(2):
    b_df.iloc[i,:] = a_df.iloc[0,i*4:(i+1)*4]

Sadece bana aşağıdaki sonuçları veriyor

     0    1    2    3
0    1    2    3    4
1  NaN  NaN  NaN  NaN

Ama değiştim zaman b_df.iloc[i,:]için b_df.iloc[i][:]. Sonuç aşağıdaki gibi doğru, istediğim bu

   0  1  2  3
0  1  2  3  4
1  5  6  7  8

Herkes bana açıklayabilir misiniz neyi arasındaki fark .iloc[i,:]ve .iloc[i][:]ve neden .iloc[i][:]yukarıda ama benim örnekte çalıştı.iloc[i,:]


Bu meraklı. b_df.iloc[1] = a_df.iloc[0, 4:8]atar endeksi ile bir dizi [4, 5, 6, 7]indeksi olan bir dizi [0, 1, 2, 3]. Hiçbir çakışma yoktur, bu nedenle NaNtüm öğelere atanır. Bu noktaya kadar bana mantıklı geliyor. Ama senin gibi ben niye belirsiz duyuyorum b_df.iloc[1][:] = ...davranacağını nesneleri farklı-teftiş b_df.iloc[1]ve b_df.iloc[1][:]indeksleri arasında hiçbir fark ortaya koymaktadır. En iyi tahminim, doğrudan bir kopyaya ( [:]) atanmasının, tahsis eden kişinin dizinini göz ardı etmesini ve bu tutarsızlığı yaratmasını sağlayan Pandas tarafından özel bir durum olarak ele alınmasıdır.
Seb

Sanırım endeks ve ilk satır başarısı nedeniyle aynı endeksi vardır çünkü
Phung Duy Phong

1
Pandalar hakkında hatırlanması gereken en önemli şey, pandalardaki tüm işlemlerin 'içsel veri hizalaması' kavramını kullanarak olmasıdır. Yani pandalarla yaptığınız hemen hemen her işlem, ifadenin her iki tarafının dizinlerini de hizalar. Burada dizin 1'i kullanarak dizin 1'i ayarlamaya çalışıyorsunuz, pandalar atamanın sağ tarafında dizin 0 olmadığından nans atayacaktır. Ayrıca sütun başlıklarının da bir dizin olduğunu unutmayın. Böylece, pandalar sütun başlığını sütun başlığına hizalar.
Scott Boston

3
İkincisi, .iloc [i] [:] kullanımına indeks zincirleme denir ve genellikle pandalarda oldukça büyük bir "hayır-hayır" dır. Bir nesnenin görünümlerini oluşturan veya bellekte beklenmedik bazı sonuçlar doğurabilecek yepyeni bir nesne oluşturan pandaların olduğu bazı isuslar vardır.
Scott Boston

Lütfen tüm çalışan cevapları oylamayı ve en çok hoşunuza giden cevabı kabul etmeyi unutmayın. Muhtemelen bunu biliyorsunuz, ancak bu topluluğa hangi cevapların yararlı olduğunu bildirmek ve insanları zamanları ve çabaları için ödüllendirmek;) Bu meta.stackexchange.com/questions/5234/ ve meta.stackexchange.com/ sorular / 173399 /
alan.elkin

Yanıtlar:


3

Geri atama sırasında series.iloc[:]ve arasında çok, çok büyük bir fark vardır series[:]. (i)locher zaman atadığınız şeyin atanan kişinin diziniyle eşleşip eşleşmediğini kontrol eder. Bu arada, [:]sözdizimi, dizin hizalamasını atlayarak temeldeki NumPy dizisine atar.

s = pd.Series(index=[0, 1, 2, 3], dtype='float')  
s                                                                          

0   NaN
1   NaN
2   NaN
3   NaN
dtype: float64

# Let's get a reference to the underlying array with `copy=False`
arr = s.to_numpy(copy=False) 
arr 
# array([nan, nan, nan, nan])

# Reassign using slicing syntax
s[:] = pd.Series([1, 2, 3, 4], index=['a', 'b', 'c', 'd'])                 
s                                                                          

0    1
1    2
2    3
3    4
dtype: int64

arr 
# array([1., 2., 3., 4.]) # underlying array has changed

# Now, reassign again with `iloc`
s.iloc[:] = pd.Series([5, 6, 7, 8], index=[3, 4, 5, 6]) 
s                                                                          

0    NaN
1    NaN
2    NaN
3    5.0
dtype: float64

arr 
# array([1., 2., 3., 4.])  # `iloc` created a new array for the series
                           # during reassignment leaving this unchanged

s.to_numpy(copy=False)     # the new underlying array, for reference                                                   
# array([nan, nan, nan,  5.]) 

Şimdi farkı anladığınıza göre, kodunuzda neler olduğuna bakalım. Ne atadığınızı görmek için döngülerinizin RHS'sini yazdırmanız yeterlidir:

for i in range(2): 
    print(a_df.iloc[0, i*4:(i+1)*4]) 

# output - first row                                                                   
0    1
1    2
2    3
3    4
Name: 0, dtype: int64
# second row. Notice the index is different
4    5
5    6
6    7
7    8
Name: 0, dtype: int64   

İçin atarken b_df.iloc[i, :]ikinci tekrarında, hiçbir şey atanır, böylece indeksleri farklıdır ve sadece NaN'ler bkz. Ancak, değişen b_df.iloc[i, :]için b_df.iloc[i][:]indeksleme hizalama baypas edilir böylece, altta yatan NumPy diziye atamak anlamına gelecektir. Bu işlem şu şekilde daha iyi ifade edilir:

for i in range(2):
    b_df.iloc[i, :] = a_df.iloc[0, i*4:(i+1)*4].to_numpy()

b_df                                                                       

   0  1  2  3
0  1  2  3  4
1  5  6  7  8

Ayrıca , bunun iyi bir şey olmayan ve aynı zamanda kodunuzu okumayı ve anlamayı zorlaştıran bir tür zincirleme görev olduğunu belirtmek gerekir.


1
Şimdi anlıyorum, teşekkür ederim. Ödül vermeden önce, bunun için bir referans ekleyebilir misiniz: " [:]sözdizimi temel NumPy dizisine atar"?
Seb

@Seb Belgede bununla ilgili referanslar bulamayacaksınız çünkü biraz uygulama detayı. GitHub'da bundan sorumlu olan kodu bulmak daha kolay olabilir, ancak en kolay yolun sadece ne olduğunu göstermek olduğunu düşünüyorum. Cevabımın üstündeki küçük örneği, yeniden atama sırasında farklı dizinin nasıl manipüle edildiğini göstermek için düzenledim. Umarım işleri daha açık hale getirir!
cs95

Çok teşekkür ederim! Şimdi çok daha net.
Tommy Yip

0

Fark, ilk durumda Python yorumlayıcısının kodu şu şekilde yürütmesidir:

b_df.iloc[i,:] = a_df.iloc[0,i*4:(i+1)*4]
#as
b_df.iloc.__setitem__((i, slice(None)), value)

burada değer denklemin sağ tarafı olacaktır. İkinci durumda Python yorumlayıcısı kodu şu şekilde yürüttü:

b_df.iloc[i][:] = a_df.iloc[0,i*4:(i+1)*4]
#as
b_df.iloc.__getitem__(i).__setitem__(slice(None), value)

burada tekrar değer denklemin sağ tarafı olacaktır.

Bu iki durumun her birinde, setitem içinde anahtarlar (i, dilim (Yok)) ve dilim (Yok) arasındaki farktan dolayı farklı bir yöntem çağrılır . Bu nedenle farklı davranışlarımız vardır.


b_df.iloc[i]ve b_df.iloc[i][:]aynı endekslere sahip. Neden biriyle eşleşmeyen dizine sahip bir diziyi diğerine atayamazsınız?
Seb

ilk durumda, ikinci one_setitem_slice çağrıda _set_item çağrı olurdu. Yani, bu yöntemlerin farkı nedeniyle şüpheli yukarıdaki davranış var
MaPy

0

Herkes bana ne arasındaki fark açıklayabilir misiniz .iloc[i,:]ve .iloc[i][:]bir

Arasındaki fark .iloc[i,:]ve.iloc[i][:]

Bu durumda, satırın tüm ( ) sütunlarını seçerek .iloc[i,:]doğrudan belirli bir özelliğine erişirseniz . Bildiğim kadarıyla, 2. boyutu belirtilmemiş ( ) bırakmak eşdeğerdir .DataFrame:i.iloc[i]

Durumunda arasında .iloc[i][:]bir 2 zincirleme işlemleri gerçekleştiriyorsunuz. Böylece, sonucu .iloc[i]bundan etkilenecektir [:]. Ayarlanan değerlere bu Kullanarak Pandalar kendisi tarafından teşvik edilmez burada bunu kullanmamalısınız nedenle, bir uyarı ile:

Bir ayar işlemi için bir kopyanın veya referansın döndürülüp döndürülmediği bağlama göre değişebilir. Buna bazen zincirleme görev denir ve bundan kaçınılmalıdır


... ve .iloc[i][:]yukarıdaki örneğimde neden çalıştım ama.iloc[i,:]

OP yorumlarında @Scott'un belirttiği gibi, veri hizalama içseldir , bu nedenle =sol tarafta yoksa , sağ tarafındaki dizinler dahil edilmez. Bu yüzden NaN2. sırada değerler var .

Yani, şeyleri açık bırakmak için şunları yapabilirsiniz:

for i in range(2):
    # Get the slice
    a_slice = a_df.iloc[0, i*4:(i+1)*4]
    # Reset the indices
    a_slice.reset_index(drop=True, inplace=True)
    # Set the slice into b_df
    b_df.iloc[i,:] = a_slice

Veya şunu listkullanmak yerine dönüştürebilirsiniz reset_index:

for i in range(2):
    # Get the slice
    a_slice = a_df.iloc[0, i*4:(i+1)*4]
    # Convert the slice into a list and set it into b_df
    b_df.iloc[i,:] = list(a_slice)
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.