पंडों में [:] बनाम iloc [:] के साथ अलग-अलग परिणाम क्यों दिए गए हैं?


13

ilocपंडों में अलग-अलग अनुक्रमण विधियों से मैं इतना भ्रमित हूं ।

मान लीजिए कि मैं 1-डी डेटाफ़्रेम को 2-डी डेटाफ़्रेम में बदलने की कोशिश कर रहा हूं। पहले मेरे पास निम्नलिखित 1-डी डेटाफ्रेम है

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

और मैं उस 2-डी डेटाफ्रेम में आकार के साथ परिवर्तित करने जा रहा हूं 2x4। मैं निम्नलिखित के रूप में 2-डी डेटाफ़्रेम निर्धारित करके शुरू करता हूं:

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

तब मैं मदद मुझे परिवर्तित करने के लिए लूप का उपयोग a_df(1-घ) करने के लिए b_dfनिम्न कोड के साथ (2-घ)

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

यह केवल मुझे निम्नलिखित परिणाम देता है

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

लेकिन जब मैं बदल b_df.iloc[i,:]गया b_df.iloc[i][:]। परिणाम निम्नलिखित की तरह सही है, जो मैं चाहता हूं

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

क्या कोई मुझे समझा सकता है कि क्या अंतर है .iloc[i,:]और क्या .iloc[i][:]है, और .iloc[i][:]ऊपर मेरे उदाहरण में क्यों काम किया लेकिन नहीं.iloc[i,:]


यह जिज्ञासु है। b_df.iloc[1] = a_df.iloc[0, 4:8]असाइन सूचकांक के साथ एक श्रृंखला [4, 5, 6, 7]सूचकांक के साथ एक श्रृंखला के लिए [0, 1, 2, 3]। ओवरलैप नहीं है इसलिए NaNसभी तत्वों को सौंपा गया है। इस बिंदु तक यह मेरे लिए समझ में आता है। लेकिन आप की तरह मैं इस बात पर अस्पष्ट हूं कि b_df.iloc[1][:] = ...अलग-अलग व्यवहार क्यों करता है- वस्तुओं का निरीक्षण करना b_df.iloc[1]और b_df.iloc[1][:]सूचकांकों के बीच कोई अंतर नहीं बताता है। मेरा सबसे अच्छा अनुमान यह होगा कि एक कॉपी ( [:]) को सीधे असाइन करना पंडों द्वारा एक विशेष मामले के रूप में माना जाता है जो इसे असाइन करने वाले के सूचकांक को अनदेखा करता है और यह विसंगति पैदा करता है।
सेब

मुझे लगता है कि यह सूचकांक में आगे बढ़ा हुआ है, और पहली पंक्ति की सफलता है क्योंकि इसमें एक ही सूचकांक है
फोंग

1
पंडों के बारे में मुझे याद रखने वाली मुख्य बात यह है कि पंडों में ज्यादातर सभी ऑपरेशन 'इंस्ट्रोनिक डेटा अलाइनमेंट' नामक अवधारणा का उपयोग करते हैं। मतलब कि लगभग कोई भी ऑपरेशन जो आप पांडा के साथ करते हैं, बयान के दोनों किनारों के अनुक्रमणिका को संरेखित करेगा। यहां आप इंडेक्स 0 का उपयोग करके इंडेक्स 1 सेट करने की कोशिश कर रहे हैं, पैंड्स नेन्स को असाइन करेंगे क्योंकि उस असाइनमेंट के दाईं ओर कोई इंडेक्स 0 नहीं है। यह भी याद रखें कि कॉलम हेडर भी एक सूचकांक है। तो, पांडा कॉलम हेडर को कॉलम हेडर संरेखित करेगा।
स्कॉट बोस्टन

3
दूसरे, .iloc का उपयोग करते हुए [i] [:] को इंडेक्स चेनिंग कहा जाता है और यह आमतौर पर पांडा में एक बहुत बड़ा "नहीं-नहीं" है। पंडों के पास कुछ विचार होते हैं जो किसी वस्तु के दृश्य बनाते हैं या स्मृति में एक बिलकुल नई वस्तु बनाते हैं जिससे कुछ अप्रत्याशित परिणाम प्राप्त हो सकते हैं।
स्कॉट बोस्टन

कृपया सभी काम करने के उत्तरों को उभारना न भूलें, और आपको जो सबसे अधिक पसंद है उसे स्वीकार करें। शायद आप यह जानते हैं, लेकिन यह समुदाय को यह बताने के लिए है कि कौन से उत्तर उपयोगी थे और लोगों को उनके समय और प्रयास के लिए पुरस्कृत करने के लिए;) इस meta.stackexchange.com/questions/5234/ और meta.stackexchange.com/ देखें। प्रश्न / 173399 /
alan.elkin

जवाबों:


3

वहाँ के बीच एक बहुत, बहुत बड़ा अंतर है series.iloc[:]और series[:], जब वापस बताए। (i)locहमेशा यह सुनिश्चित करने के लिए जांचता है कि आप जो भी असाइन कर रहे हैं वह असाइनमेंट के सूचकांक से मेल खाता है। इस बीच, [:]सिंटैक्स अंतर्निहित संरेखण सरणी को निर्दिष्ट करता है, सूचकांक संरेखण को दरकिनार करता है।

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.]) 

अब जब आप अंतर समझ गए हैं, तो आइए देखें कि आपके कोड में क्या होता है। अपने लूप्स के आरएचएस को देखें कि आप क्या काम कर रहे हैं:

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   

b_df.iloc[i, :]दूसरे पुनरावृत्ति में असाइन करते समय , इंडेक्स अलग होते हैं इसलिए कुछ भी असाइन नहीं किया जाता है और आप केवल NaNs देखते हैं। हालाँकि, बदलने b_df.iloc[i, :]का b_df.iloc[i][:]मतलब होगा कि आप अंतर्निहित NumPy सरणी को असाइन करते हैं, इसलिए अनुक्रमण संरेखण को बाईपास किया जाता है। इस ऑपरेशन को बेहतर तरीके से व्यक्त किया गया है

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

यह भी ध्यान देने योग्य है कि यह जंजीर असाइनमेंट का एक रूप है, जो अच्छी बात नहीं है , और यह आपके कोड को पढ़ने और समझने के लिए कठिन बनाता है।


1
अब मैं इसे समझता हूं, धन्यवाद। इससे पहले कि मैं बाउंटी को पुरस्कार दूं, क्या आप इसके लिए एक संदर्भ जोड़ सकते हैं: " [:]सिंटैक्स अंतर्निहित NumPy सरणी को असाइन करता है"?
सेब

@ सीब आपको वास्तव में प्रलेखन में इसके संदर्भ नहीं मिलेंगे क्योंकि यह कुछ हद तक कार्यान्वयन विवरण है। इसके लिए ज़िम्मेदार GitHub पर कोड ढूंढना आसान हो सकता है, लेकिन मुझे लगता है कि सबसे आसान तरीका यह है कि जो होता है उसे प्रदर्शित करें। मैंने अपने उत्तर के शीर्ष पर छोटे उदाहरण को दिखाया है कि विभिन्न प्रकार के पुनर्मूल्यांकन के दौरान अंतर्निहित सरणी में हेरफेर कैसे किया जाता है। आशा है कि चीजों को स्पष्ट करता है!
CS95

आपको बहुत - बहुत धन्यवाद! यह अब इतना साफ है।
टॉमी यिप

0

अंतर यह है कि पहले मामले में पायथन दुभाषिया ने कोड को इस प्रकार निष्पादित किया:

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

जहां मान समीकरण के दाहिने हाथ की ओर होगा। जबकि दूसरे मामले में पायथन इंटरप्रेटर ने कोड को इस प्रकार निष्पादित किया:

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

जहां फिर से मूल्य समीकरण के दाहिने हाथ की ओर होगा।

उन दो मामलों में कुंजियों में अंतर (i, slice ( none )) और slice ( none) के कारण एक अलग विधि को अंदर की विधि कहा जाएगा इसलिए हमारा अलग व्यवहार है।


b_df.iloc[i]और b_df.iloc[i][:]हालांकि एक ही सूचकांक है। आप एक के लिए नॉन-मैचिंग इंडेक्स के साथ एक श्रृंखला क्यों असाइन कर सकते हैं लेकिन दूसरे को नहीं?
सेब

पहले मामले में _set_item को कॉल किया जाएगा दूसरे one_setitem_slice को कॉल किया जाएगा। इसलिए, उन तरीकों के अंतर के कारण संदेह है जो हमारे पास उपरोक्त व्यवहार हैं
मैपी

0

क्या कोई मुझे समझा सकता है कि क्या अंतर है .iloc[i,:]और क्या .iloc[i][:]है

.iloc[i,:]और के बीच का अंतर.iloc[i][:]

.iloc[i,:]आप के मामले में सीधे वें के DataFrameसभी ( :) कॉलम का चयन करके, के एक विशिष्ट कब्जे तक पहुंच रहे हैं i। जहाँ तक मुझे पता है, यह दूसरे आयाम को अनिर्दिष्ट ( .iloc[i]) छोड़ने के बराबर है ।

.iloc[i][:]आप के मामले में एक 2 जंजीर संचालन कर रहे हैं। तो, .iloc[i]इच्छा का परिणाम फिर से प्रभावित होगा [:]। सेट मूल्यों को यह का उपयोग करते हुए पांडा अपने आप में हतोत्साहित किया जाता है यहाँ , एक चेतावनी के साथ ताकि आप इसे उपयोग नहीं करना चाहिए:

एक सेटिंग ऑपरेशन के लिए एक प्रतिलिपि या एक संदर्भ लौटाया जाता है, संदर्भ पर निर्भर हो सकता है। इसे कभी-कभी जंजीर असाइनमेंट कहा जाता है और इसे टाला जाना चाहिए


... और .iloc[i][:]ऊपर मेरे उदाहरण में काम क्यों नहीं किया गया.iloc[i,:]

जैसा कि @ ओप्स ने ओपी टिप्पणियों में उल्लेख किया है, डेटा संरेखण आंतरिक है , इसलिए =यदि बाईं ओर मौजूद नहीं हैं , तो दाईं ओर अनुक्रमणिका को शामिल नहीं किया जाएगा। यही कारण है कि NaNदूसरी पंक्ति में मान हैं ।

इसलिए, चीजों को स्पष्ट छोड़ने के लिए, आप निम्नानुसार कर सकते हैं:

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

या आप listका उपयोग करने के बजाय परिवर्तित कर सकते हैं 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)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.