본문 바로가기

Python

SettingWithCopyWarning

1. stackoverflow의 유용성이야 다시 강조할 필요도 없지만

    데이터 처리 중 만나게 된 settingwithcopywarning.

https://stackoverflow.com/questions/20625582/how-to-deal-with-settingwithcopywarning-in-pandas

 

How to deal with SettingWithCopyWarning in Pandas?

Background I just upgraded my Pandas from 0.11 to 0.13.0rc1. Now, the application is popping out many new warnings. One of them like this: E:\FinReporter\FM_EXT.py:449: SettingWithCopyWarning: A va...

stackoverflow.com

 

2. 구체적인 사례를 보자

   CFTC 자료를 가지고 투기세력의 순매수 포지션과 변화를 확인하기 위해 작업 중인데

   CFTC 자료는 엑셀 한 시트에 데이터가 다 들어가 있다. 

  https://www.cftc.gov/MarketReports/CommitmentsofTraders/HistoricalCompressed/index.htm

 

Historical Compressed | CFTC

Disaggregated Futures Only Reports: The complete Disaggregated Commitments of Traders Futures Only reports file from September 2009 is included by year. Reports By Year     2020 (Text, Excel) 2019 (Text, Excel) 2018 (Text, Excel) 2017 (Text, Excel) 2016

www.cftc.gov

2-1. CFTC 자료를 읽어들이면

1
COT = pd.read_excel("D:\\category\\CFTC\\new\\option\\annual.xls")
cs

 

   아래와 같다.   

 

 

2-2. 품목을 확인하고 싶다면 

1
2
for name, group in COT.groupby('Market_and_Exchange_Names'):
    print(name)
cs

 

     하면 된다.

 

 

2-3. 2020년 파일은 1년 기간이기 때문에 대부분 품목의 갯수는 같지만 과거 자료를 확인해보면

      없다 사라지는 경우도 많다. 

      그래서 변수에 따른 자료 개수를 확인하기 위해

      변수별로 그룹화해서 오름차순 정렬해 보면

1
COT.groupby("Market_and_Exchange_Names").size().nlargest(20)
cs

     

      내림차순은 smallest() 를 사용한다. 

 

 

 

2-4. 위 품목별 투기세력의 순매수 포지션을 구하기 위해서는 

1
COT['Netlong'= COT['M_Money_Positions_Long_ALL'- COT['M_Money_Positions_Short_ALL'
cs

     

     위와 같은 단순 계산으로 새로운 컬럼을 만들면 되고

     만약 매수/매도 포지션을 구하기 위해서는 매도 포지션이 0인 경우를 고려해서

1
2
COT['M_Money ratio']= np.where(COT['M_Money_Positions_Short_ALL'== 0" ", COT['M_Money_Positions_Long_ALL'/ COT['M_Money_Positions_Short_ALL'] )
 
cs

     

     위와 같이 해주면 된다.

 

 

3. 그렇다면 settingwihtcopywarning은 어디서 나타났을까?

   순매수 포지션의 전주 변화를 살펴보기 위해

   - 사실 이런 단순 계산의 편의성을 위해 xlwings 라이브러리를 이용하고 있기 때문에 엑셀 작업이 훨씬 간단하지만 - 

1
2
COT['Netlong_change'= COT['Netlong'- COT['Netlong'].shift(1)
 
cs

   

   위와 같이 계산하게 되면 결과값이 이상하다. 

   왜?

   데이터가 행으로 일자로 정리되어 있기 때문에 위와 같은 코드는 단순히 한 행이 모두 이동해

   품목이 섞이기 때문이다. 

   그래서, 품목별로 나눈 후에 계산을 해야한다. 

   여기서 활용되는 것이 isin 함수

1
2
COT[COT["Market_and_Exchange_Names"].isin(["WHEAT-SRW - CHICAGO BOARD OF TRADE"])]
 
cs

   

   위와 같이 품목별로 나누어 준다. 

   그런데 

1
COT[COT['Market_and_Exchange_Names'].isin(['WHEAT-SRW - CHICAGO BOARD OF TRADE'])]['netlong_change'= COT[COT['Market_and_Exchange_Names'].isin(['WHEAT-SRW - CHICAGO BOARD OF TRADE'])]['Netlong'- COT[COT['Market_and_Exchange_Names'].isin(['WHEAT-SRW - CHICAGO BOARD OF TRADE'])]['Netlong'].shift(1)
cs

 

  위와 같이 작성하면 settingwithcopywarning 오류가 나면서 계산이 안된다.  

  이유는 1번 stackoverflow를 읽어보면 자세하게 설명이 되어 있다. 

 

4. 해결책

1
2
3
4
5
df = COT[COT['Market_and_Exchange_Names'].isin(['WHEAT-SRW - CHICAGO BOARD OF TRADE'])]['Netlong']- COT[COT['Market_and_Exchange_Names'].isin(['WHEAT-SRW - CHICAGO BOARD OF TRADE'])]['Netlong'].shift(1)
df1 = pd.DataFrame(df)
df1.columns = ['Netlong_change']
df2 = pd.merge(COT[COT['Market_and_Exchange_Names'].isin(['WHEAT-SRW - CHICAGO BOARD OF TRADE'])], df1, left_index= True, right_index = True)
df2
cs

   

   다른 방법이 있는지는 잘 모르겠지만 여튼 위와 같은 형태로.