DRM 걸린 엑셀 파일을 판다스 데이터프레임으로 불러오기
업데이트:
이전글 : xlwings의 Book, Sheet, Range 객체 다루기
엑셀의 표를 Series / DataFrame 객체로 변환하기
지난 포스팅에서 xlwings로 생성한 Range 객체의 value 속성을 통해서 엑셀 파일에 담긴 자료들을 파이썬으로 가져오는 과정을 살펴봤다. 이 경우 자료값들은 파이썬의 ‘리스트’ 또는 ‘리스트 of 리스트’ 형태를 취하게 된다. 이를 판다스의 시리즈나 데이터프레임 객체로 변환하려면, 인덱스와 컬럼명을 별도로 지정해줘야 하는 불편함이 있다. 다행히 xlwings에서는 Range 객체를 곧바로 시리즈/데이터프레임으로 변환하는 기능이 존재한다.
Range 객체의 형태변환 : options 메서드
이전 포스팅에서의 실습을 이어나가보자. 먼저, 첫번째 시트(sh1)에 종목코드와 종목명이 있는 범위(A1:B7)를 다음과 같은 방법을 통해 딕셔너리 자료형으로 변환할 수 있다.
dtn = sh1['A2:B7'].options(dict).value
dtn
{'A005930': '삼성전자',
'A051910': 'LG화학',
'A035420': 'NAVER',
'A005380': '현대차',
'A035720': '카카오',
'A068270': '셀트리온'}
위와 같이 엑셀의 특정 범위를 Range 객체로 만든 다음, .options(자료형이름).value
를 붙여주면 지정한 자료형에 따라
값을 반환한다. 자료형 이름으로 dict
를 입력하면 해당 범위의 첫번째 열을 키(key), 나머지 열을 값(value)으로 갖는
딕셔너리를 반환한다. (이미 확인했듯이 options 메서드를 거치지 않고 바로 .value
를 붙이면 리스트 자료형으로 반환된다.)
판다스의 시리즈/데이터프레임 객체로 변환하는 것도 같은 방법으로 가능하다. 먼저 판다스 라이브러리를 import 하고(약칭 pd), 자료형 이름에 pd.Series(1차원 자료) 또는 pd.DataFrame(2차원 자료)을 입력하면 된다.
import pandas as pd
sr = sh1['A1:B7'].options(pd.Series).value
sr
종목코드
A005930 삼성전자
A051910 LG화학
A035420 NAVER
A005380 현대차
A035720 카카오
A068270 셀트리온
Name: 종목명, dtype: object
df = sh1['A1:E7'].options(pd.DataFrame).value
df
종목명 | 주가(원) | 시가총액(백만원) | 섹터 | |
---|---|---|---|---|
종목코드 | ||||
A005930 | 삼성전자 | 82600.0 | 493104039.0 | 전기전자 |
A051910 | LG화학 | 941000.0 | 66427395.0 | 화학 |
A035420 | NAVER | 398000.0 | 65376831.0 | IT |
A005380 | 현대차 | 242000.0 | 51707701.0 | 자동차 |
A035720 | 카카오 | 504000.0 | 44689512.0 | IT |
A068270 | 셀트리온 | 318500.0 | 43858542.0 | 바이오 |
엑셀 범위에서 기본적으로 첫번째 열이 인덱스(index), 첫번째 행이 컬럼명(columns)으로 지정된다.
Range 확장하기 : expand 매개변수
다음과 같은 상황을 가정해보자. 당신은 매일 사내 업무시스템의 특정 화면에서 자료를 내려받아서 일일 보고를 위한
데이터 산출 작업을 하고 있다. 지금까지 실습했던 주식_종목_리스트.xlsx
파일과 컬럼명은 동일하지만,
아래 그림과 같이 매일 종목의 종류와 수만 바뀐다고 하자.
1일차 자료(다운로드) | 2일차 자료(다운로드) |
3일차 자료(다운로드) | 4일차 자료(다운로드) |
위에서 실습했던 내용을 아래와 같이 함수로 만들어 호출해보자.
def automate_excel(file_name):
bk = xw.Book(file_name)
sh = bk.sheets(1)
df = sh['A1:E7'].options(pd.DataFrame).value
return df
df_auto = automate_excel('주식_종목_리스트2.xlsx')
df_auto
종목명 | 주가(원) | 시가총액(백만원) | 섹터 | |
---|---|---|---|---|
종목코드 | ||||
A000270 | 기아 | 85500.0 | 34658566.0 | 경기소비재 |
A036570 | 엔씨소프트 | 885000.0 | 19429309.0 | IT |
A032830 | 삼성생명 | 78000.0 | 15600000.0 | 금융 |
NaN | None | NaN | NaN | None |
NaN | None | NaN | NaN | None |
NaN | None | NaN | NaN | None |
엑셀파일명을 인수로 입력하면 A1:E7
범위 내의 표를 데이터프레임 객체로 변환해주는 함수다. 문제는 2일차부터는
표의 범위가 계속 달라지기 때문에 저대로는 함수를 사용할 수가 없다는 것이다.
여기서 options 메서드의 expand
매개변수를 활용하면 매일 변동하는 표의 범위를 자동으로 인식할 수 있다.
expand
의 인수로는 ‘down’, ‘right’, ‘table’이 들어갈 수 있다. 이는 미리 설정된
Range 객체의 범위를 아래쪽(‘down’) 또는 오른쪽(‘right’), 혹은 양쪽 모두(‘table’)로 확장하는 기능이다. 아래의
예시 코드에서 df1
~ df4
는 모두 같은 표를 가리킨다.
df1 = sh1['A1:E7'].options(pd.DataFrame).value
df2 = sh1['A1:E1'].options(pd.DataFrame, expand='down')
df3 = sh1['A1:A7'].options(pd.DataFrame, expand='right')
df4 = sh1['A1'].options(pd.DataFrame, expand='table')
두번째 줄의 코드를 해석해보면, 1) 엑셀 상에서 A1:E1
에 해당하는 범위를 선택하고 2) Ctrl + Shift + 방향키 ↓
를 눌러서
선택 범위를 확장한 다음 3) 확장된 범위 내의 자료값을 데이터프레임으로 불러온다는 의미다. 세번째 줄은 방향키 →
, 네번째 줄은 방향키 ↓
과 방향키 →
를
연속으로 누른 경우라고 보면 된다.
앞에서 매일 컬럼명은 동일하나 종목의 종류와 수만 바뀐다고 가정했으므로, 자동화 함수를 다음과 같이 수정하면 어떤 날짜에도 사용가능하게 된다.
def automate_excel(file_name):
bk = xw.Book(file_name)
sh = bk.sheets(1)
df = sh['A1'].options(pd.DataFrame, expand='table').value
# 또는 sh['A1:E1'].options(pd.DataFrame, expand='down').value
return df
df_auto = automate_excel('주식_종목_리스트.xlsx')
df_auto2 = automate_excel('주식_종목_리스트2.xlsx')
df_auto3 = automate_excel('주식_종목_리스트3.xlsx')
df_auto4 = automate_excel('주식_종목_리스트4.xlsx')
댓글남기기