부모 데이터 프레임에서 하위 데이터 프레임을 선택할 때 일부 프로그래머가 .copy()
메서드를 사용하여 데이터 프레임의 복사본을 만드는 것을 알았습니다 . 예를 들어
X = my_dataframe[features_list].copy()
… 단지
X = my_dataframe[features_list]
왜 데이터 프레임의 사본을 만들고 있습니까? 사본을 만들지 않으면 어떻게됩니까?
답변
이것은 바울의 대답으로 확장됩니다. 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
답변
복사하지 않으면 dataFrame을 다른 이름으로 할당하더라도 색인을 다른 곳에서 조작 할 수 있기 때문입니다.
예를 들면 다음과 같습니다.
df2 = df
func1(df2)
func2(df)
func1은 df2를 수정하여 df를 수정할 수 있으므로 다음을 피하십시오.
df2 = df.copy()
func1(df2)
func2(df)
답변
사본이나 뷰를 반환하는 것은 인덱싱의 종류에 달려 있다는 점을 언급해야합니다.
팬더 문서는 다음과 같이 말합니다.
뷰와 사본 반환
데이터에 대한 뷰가 반환되는시기에 대한 규칙은 전적으로 NumPy에 따라 다릅니다. 인덱싱 작업에 레이블 배열 또는 부울 벡터가 포함될 때마다 결과가 복사됩니다. df.ix [3 : 6] 또는 df.ix [:, ‘A’]와 같은 단일 레이블 / 스칼라 인덱싱 및 슬라이싱을 사용하면 뷰가 반환됩니다.
답변
주요 목적은 체인 인덱싱을 피하고를 제거하는 것 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
답변
일반적으로 원본이 더 이상 필요하지 않고 조작 된 버전으로 진행하려는 경우를 제외하고는 원본 데이터 프레임보다 사본에서 작업하는 것이 더 안전합니다. 일반적으로 원본 데이터 프레임을 조작 된 버전 등과 비교할 때 여전히 사용합니다. 따라서 대부분의 사람들은 복사 작업을하고 마지막에 병합합니다.
답변
아래와 같이 데이터 프레임이 있다고 가정합니다.
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
, 지금 df1
과 df2
다른 것으로 간주됩니다 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