[:] 대 iloc [:]로 할당하면 판다에서 다른 결과가 나오는 이유는 무엇입니까?


13

iloc팬더에서 사용하는 다른 인덱싱 방법과 혼동됩니다 .

1-d 데이터 프레임을 2-d 데이터 프레임으로 변환하려고한다고 가정 해 봅시다. 먼저 다음 1-d 데이터 프레임이 있습니다.

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

그런 다음 for-loop를 사용하여 다음 코드 로 a_df(1-d)를 b_df(2-d)로 변환하는 데 도움이 됩니다.

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]index [4, 5, 6, 7]가 있는 시리즈를 index 가있는 시리즈에 할당합니다 [0, 1, 2, 3]. 오버랩이 없으므로 NaN모든 요소에 할당됩니다. 이 시점까지는 나에게 의미가 있습니다. 그러나 당신처럼 나는 이유에 불분명 오전 b_df.iloc[1][:] = ...동작합니다이 개체를 다른-검사 b_df.iloc[1]b_df.iloc[1][:]인덱스 사이의 차이를 알 수 없습니다. 필자의 가장 좋은 추측은 사본 ( [:])에 직접 할당 하는 것이 팬더에 의해 특별한 경우로 간주되어 양수인의 색인을 무시 하고이 불일치를 만드는 것입니다.

인덱스 때문이라고 생각합니다. 인덱스가 같기 때문에 첫 번째 행 성공
Phung Duy Phong

1
팬더에 대해 기억해야 할 핵심은 팬더의 모든 작업은 'intrinic data alignment'라는 개념을 사용한다는 것입니다. 팬더로 수행하는 거의 모든 작업은 명령문의 양쪽 인덱스를 정렬합니다. 인덱스 0을 사용하여 인덱스 1을 설정하려고합니다. 팬더는 해당 할당의 오른쪽에 인덱스 0이 없기 때문에 nan을 할당합니다. 또한 열 머리글도 색인이라는 것을 기억하십시오. 따라서 팬더는 열 머리글을 열 머리글에 정렬합니다.
Scott Boston

3
둘째, .iloc [i] [:]를 사용하는 것을 인덱스 체인이라고하며 팬더에서는 일반적으로 "no-no"입니다. 팬더가 객체의 뷰를 생성하거나 메모리에 새로운 객체를 생성하여 예기치 않은 결과가 발생할 수 있습니다.
Scott Boston

모든 작업 답변을 찬성하고 가장 좋아하는 답변을 수락하는 것을 잊지 마십시오. 아마도 당신은 이것을 알고 있지만 이것은 커뮤니티가 어떤 답변이 유용했는지 알려주고 시간과 노력에 대해 사람들에게 보상하는 것입니다.) meta.stackexchange.com/questions/5234/ 및 meta.stackexchange.com/ 질문 / 173399 /
alan.elkin

답변:


3

사이에는 매우 큰 차이가 있습니다 series.iloc[:]series[:]다시 할당 할 때 와와 ( 있습니다. (i)loc할당하려는 항목이 양수인의 색인과 일치하는지 항상 확인합니다. 한편, [:]구문은 인덱스 정렬을 무시하고 기본 NumPy 배열에 할당합니다.

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

차이점을 이해 했으므로 코드에서 어떤 일이 발생하는지 살펴 보겠습니다. 루프의 RHS를 인쇄하여 할당 대상을 확인하십시오.

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, :]두 번째 반복에서 할당 할 때 인덱스가 다르므로 할당 된 것이 없으며 NaN 만 표시됩니다. 그러나 변경 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 배열에 할당 됨 "에 대한 참조를 추가 할 수 있습니까?
Seb

@Seb 구현 세부 사항이기 때문에 문서에서 실제로 이것에 대한 참조를 찾을 수는 없습니다. 이것을 담당하는 GitHub에서 코드를 찾는 것이 더 쉬울 수 있지만 가장 쉬운 방법은 무슨 일이 일어나는지 보여주는 것입니다. 나는 다른 종류의 재 할당하는 동안 기본 배열이 어떻게 조작되는지를 보여주기 위해 대답의 맨 위에 작은 예제를 편집했습니다. 그것이 더 명확 해지기를 바랍니다!
cs95

정말 고맙습니다! 지금은 훨씬 더 명확합니다.
Tommy Yip

0

차이점은 첫 번째 경우 Python 인터프리터가 코드를 다음과 같이 실행한다는 것입니다.

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)의 차이로 인해 setitem 내에서 다른 메소드가 호출 되므로 동작이 다릅니다.


b_df.iloc[i]그리고 b_df.iloc[i][:]비록 같은 인덱스를 가지고있다. 왜 일치하지 않는 인덱스가있는 시리즈를 다른 하나에는 할당 할 수 없습니까?

첫 번째 경우 _set_item이 호출되고 두 번째 one_setitem_slice가 호출됩니다. 따라서 이러한 방법의 차이로 인해 위와 같은 동작이 발생합니다.
MaPy

0

사람이 나에게 무엇의 차이를 설명 할 수 .iloc[i,:].iloc[i][:]입니다

차이점 .iloc[i,:].iloc[i][:]

의 ( ) 열을 모두 선택하여 .iloc[i,:]의 특정 위치에 직접 액세스 하는 경우DataFrame:i 번째 행 . 내가 아는 한, 2 차원을 지정하지 않은 상태 (.iloc[i] ) .

.iloc[i][:]2 개의 체인 작업을 수행하는 경우 . 따라서의 결과는의 .iloc[i]영향을받습니다 [:]. 이 값을 사용하여 값을 설정하는 것은 Pandas 자체 에서 경고와 함께 권장하지 않으므로 사용해서는 안됩니다.

설정 조작에 대해 사본 또는 참조가 리턴되는지 여부는 컨텍스트에 따라 달라질 수 있습니다. 이를 체인 할당이라고도하며 피해야합니다


... 그리고 왜 .iloc[i][:]위의 예에서 효과가 있었습니까?.iloc[i,:]

OP 주석에서 @Scott이 언급했듯이 데이터 정렬은 본질적 이므로 =왼쪽에없는 경우 오른쪽의 인덱스는 포함되지 않습니다. 이것이 이유입니다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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.