왜 판다에서 데이터 프레임의 사본을 만들어야합니까?


189

부모 데이터 프레임에서 하위 데이터 프레임을 선택할 때 일부 프로그래머가 .copy()메서드를 사용하여 데이터 프레임의 복사본을 만드는 것을 알았습니다 . 예를 들어

X = my_dataframe[features_list].copy()

... 단지

X = my_dataframe[features_list]

왜 데이터 프레임의 사본을 만들고 있습니까? 사본을 만들지 않으면 어떻게됩니까?


6
내 생각에 그들은 소스 데이터 프레임을 수정하지 않기 위해 특별한주의를 기울이고 있습니다. 아마도 불필요하지만 대화식으로 무언가를 함께 던질 때 미안보다 안전합니다.
Paul H

8
나는 이것이 부정적인 것을주는 바보 같은 질문이 아니라고 가정합니다.
Elizabeth Susan Joseph

답변:


207

이것은 바울의 대답으로 확장됩니다. Pandas에서 DataFrame을 인덱싱하면 초기 DataFrame에 대한 참조가 반환됩니다. 따라서 하위 집합을 변경하면 초기 DataFrame이 변경됩니다. 따라서 초기 DataFrame이 변경되지 않도록하려면 복사본을 사용하고 싶을 것입니다. 다음 코드를 고려하십시오.

df = DataFrame({'x': [1,2]})
df_sub = df[0:1]
df_sub.x = -1
print(df)

당신은 얻을 것이다:

x
0 -1
1  2

대조적으로, 다음은 df를 변경하지 않은 채로 둡니다.

df_sub_copy = df[0:1].copy()
df_sub_copy.x = -1

6
이것은 깊은 사본입니까?
bikashg

6
예. 기본 모드는 "딥"복사입니다! pandas.pydata.org/pandas-docs/stable/reference/api/…
Ambareesh

44

복사하지 않으면 dataFrame을 다른 이름으로 할당하더라도 색인을 다른 곳에서 조작 할 수 있기 때문입니다.

예를 들면 다음과 같습니다.

df2 = df
func1(df2)
func2(df)

func1은 df2를 수정하여 df를 수정할 수 있으므로 다음을 피하십시오.

df2 = df.copy()
func1(df2)
func2(df)

잠깐만 잠깐만, 왜 이런 일이 발생하는지 설명 할 수 있습니까? 이해가되지 않습니다.
NONAME

2
첫 번째 예제에서`df2 = df , both variables reference the same DataFrame instance. So any changes made to df`이거나 df2같은 객체 인스턴스로 만들어지기 때문입니다. 반면에 df2 = df.copy()제 객체 인스턴스가 생성되고, 상기 첫 번째 복사본 그러나 지금 dfdf2다른 오브젝트 인스턴스 및 변경을 참조는 각 DataFrame 인스턴스에 대하여 설명한다.
페드로

17

사본이나 뷰를 반환하는 것은 인덱싱의 종류에 달려 있다는 점을 언급해야합니다.

팬더 문서는 다음과 같이 말합니다.

뷰와 사본 반환

데이터에 대한 뷰가 반환되는시기에 대한 규칙은 전적으로 NumPy에 따라 다릅니다. 인덱싱 작업에 레이블 배열 또는 부울 벡터가 포함될 때마다 결과가 복사됩니다. df.ix [3 : 6] 또는 df.ix [:, 'A']와 같은 단일 레이블 / 스칼라 인덱싱 및 슬라이싱을 사용하면 뷰가 반환됩니다.



12

주요 목적은 체인 인덱싱을 피하고를 제거하는 것 SettingWithCopyWarning입니다.

여기서 체인 인덱싱은 dfc['A'][0] = 111

문서는 뷰와 복사본반환 할 때 체인 인덱싱을 피해야한다고 말했다 . 다음은 해당 문서에서 약간 수정 된 예입니다.

In [1]: import pandas as pd

In [2]: dfc = pd.DataFrame({'A':['aaa','bbb','ccc'],'B':[1,2,3]})

In [3]: dfc
Out[3]:
    A   B
0   aaa 1
1   bbb 2
2   ccc 3

In [4]: aColumn = dfc['A']

In [5]: aColumn[0] = 111
SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

In [6]: dfc
Out[6]:
    A   B
0   111 1
1   bbb 2
2   ccc 3

여기에 aColumn원본 DataFrame의 사본이 아닌 뷰가 있으므로 수정 aColumn하면 원본 dfc도 수정됩니다. 다음으로 행을 먼저 인덱싱하면 :

In [7]: zero_row = dfc.loc[0]

In [8]: zero_row['A'] = 222
SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

In [9]: dfc
Out[9]:
    A   B
0   111 1
1   bbb 2
2   ccc 3

이번에 zero_row는 사본이므로 원본 dfc은 수정되지 않습니다.

위의 두 예제에서 원본 DataFrame을 변경할지 여부는 모호합니다. 다음과 같이 쓸 경우 특히 위험합니다.

In [10]: dfc.loc[0]['A'] = 333
SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

In [11]: dfc
Out[11]:
    A   B
0   111 1
1   bbb 2
2   ccc 3

이번에는 전혀 작동하지 않았습니다. 여기서 우리는 변경 dfc하고 싶었지만 실제로 dfc.loc[0]사본 인 중간 값 을 수정하여 즉시 버려졌습니다. 이 같은 중간 값 여부를 예측하기 매우 어렵다 dfc.loc[0]또는 dfc['A']이 원래 DataFrame 업데이트할지 여부를 보장 할 수 없습니다, 그래서 뷰 또는 사본입니다. 이것이 체인 인덱싱을 피해야하는 이유이며 팬더는 SettingWithCopyWarning이런 종류의 체인 인덱싱 업데이트를 생성합니다.

이제는입니다 .copy(). 경고를 없애려면 의도를 명시 적으로 나타내는 사본을 만드십시오.

In [12]: zero_row_copy = dfc.loc[0].copy()

In [13]: zero_row_copy['A'] = 444 # This time no warning

사본을 수정하고 있기 때문에 원본 dfc은 변경되지 않으며 변경 될 것으로 예상되지 않습니다. 당신의 기대는 행동과 일치하면 SettingWithCopyWarning사라집니다.

원본 DataFrame을 수정하려면 다음을 사용하는 것이 좋습니다 loc.

In [14]: dfc.loc[0,'A'] = 555

In [15]: dfc
Out[15]:
    A   B
0   555 1
1   bbb 2
2   ccc 3

2

일반적으로 원본이 더 이상 필요하지 않고 조작 된 버전으로 진행하려는 경우를 제외하고는 원본 데이터 프레임보다 사본에서 작업하는 것이 더 안전합니다. 일반적으로 원본 데이터 프레임을 조작 된 버전 등과 비교할 때 여전히 사용합니다. 따라서 대부분의 사람들은 복사 작업을하고 마지막에 병합합니다.


0

아래와 같이 데이터 프레임이 있다고 가정합니다.

df1
     A    B    C    D
4 -1.0 -1.0 -1.0 -1.0
5 -1.0 -1.0 -1.0 -1.0
6 -1.0 -1.0 -1.0 -1.0
6 -1.0 -1.0 -1.0 -1.0

때 당신은 다른 만들 싶습니다 df2동일하다을 df1하지 않고,copy

df2=df1
df2
     A    B    C    D
4 -1.0 -1.0 -1.0 -1.0
5 -1.0 -1.0 -1.0 -1.0
6 -1.0 -1.0 -1.0 -1.0
6 -1.0 -1.0 -1.0 -1.0

그리고 아래처럼 df2 값만 수정하고 싶습니다

df2.iloc[0,0]='changed'

df2
         A    B    C    D
4  changed -1.0 -1.0 -1.0
5       -1 -1.0 -1.0 -1.0
6       -1 -1.0 -1.0 -1.0
6       -1 -1.0 -1.0 -1.0

동시에 df1도 변경됩니다

df1
         A    B    C    D
4  changed -1.0 -1.0 -1.0
5       -1 -1.0 -1.0 -1.0
6       -1 -1.0 -1.0 -1.0
6       -1 -1.0 -1.0 -1.0

두 개의 df가 동일 object하므로 다음을 사용하여 확인할 수 있습니다.id

id(df1)
140367679979600
id(df2)
140367679979600

그래서 그것들은 같은 객체이고 다른 하나는 같은 값을 전달할 것입니다.


우리는을 추가하는 경우 copy, 지금 df1df2다른 것으로 간주됩니다 object우리는 다른 하나는 변경되지 않습니다 그 중 하나에 동일한 변경을 할 경우.

df2=df1.copy()
id(df1)
140367679979600
id(df2)
140367674641232

df1.iloc[0,0]='changedback'
df2
         A    B    C    D
4  changed -1.0 -1.0 -1.0
5       -1 -1.0 -1.0 -1.0
6       -1 -1.0 -1.0 -1.0
6       -1 -1.0 -1.0 -1.0

언급했듯이 원본 데이터 프레임의 하위 집합을 만들 때 복사본을 추가하는 것이 안전합니다. SettingWithCopyWarning

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.