파이콘 2023에서 들은 내용과 후기입니다.
1. 짠내나는 데이터 다루기 (부제 : 제한된 메모리로 다룰 수 있는 현실적인 데이터)
- 로컬에서 큰 사이즈 데이터 다루기
- 데이터가 30G 정도 되면 클라우드에서 분산처리 함. 로컬에서 잘 하지 않음
- 그러나 그런 환경이 되지 않는다면? 제한된 장비로 어디까지 다룰 수 있는지
- 오늘 내용은 32기가 환경에서 작성
- 개인 장비는 4~64기가 정도
- 8G 환경에서 32G보다 큰 파일을, 혹은 수백~수천개 파일을 메모리에 모두 로드해야 한다면? 아예 불러오는게 안 될 수도 있음. 심지어 메모리를 데이터 처리만 하는 데 쓰는 것도 아님 (여러 앱 켜 놓음)
- 주어진 장비로 해야 한다면, 메모리 사용량을 줄이는 작업 환경으로 해야 함
- 기본적으로는 다른 프로그램 제거/비활성화. 가상 메모리 설정 변경 등
- 주피터라면 쓰지 않는 노트북 Shutdown or 주피터 재시작
- 메모리 낭비요소 제거했다면, 이제는?
sklearn
의 중장기 로드맵: pandas와의 호환성pandas
제한 사항- 데이터를 메모리에 로드. 메모리보다 더 큰 데이터는 어려움
- subset, 파생 변수 등 복사본 만들면, 메모리 더 늘어남
- 메모리 사용량 줄이기
- 샘플링. 필요한 행/열만
- 청크
- parquet 형식 사용하여 데이터 압축
- 병렬처리
- 분산처리 프레임워크
dask
,vaex
,Pyspark
등
메모리 사용 줄이는 방법
- 한번에 불러오지 못한다면, 조금씩 나누기
- 작은 크기로 축소 (행/열 제거)
- 필요한 데이터만 subset으로 가공
- Chunked Processing
- 데이터를 작은 청크로 나누어 처리
- 메모리에 한 번에 로드하지 않고, chunk size 지정하여 청크 단위로 반복적인 처리
- Iterator 활용. 각 청크는 메모리에 로드되지 않음?
- 파일 용량 줄이기 (다운캐스트)
- parquet 포맷 활용
- 열 지향 데이터 파일 형식. 열 기반 압축. 한 열은 같은 형식이기 때문에 압축에 유리
- 메타 정보를 포함하기 때문에, 아주 작은 데이터는 오히려 사이즈가 늘어날 수 있음
- Parquet Metadata: 파일의 구조, 스키마 정보, 저장된 행 수, 컬럼 정보, 압축/인코딩 방식 등 제공
- 데이터 타입 변경
- 판다스는 기본적으로
int64
/float64
. 가능하면int8
까지. object 형식인 str도 변경? - 다운캐스트 후 타입 변경하면 1/8까지 줄어들기도 함
- 애초에 불러올 때 타입 지정할 수도 있지만, 그러면 int8 이상의 데이터가 있을 수 있음
- 청크로 앞부분만 불러와서 타입 확정하고, 전체 데이터에 적용할 수도 있음
- 다운사이징 연습: 캐글 데이터
- Hotel Booking Demand: 29MB -> 5.6MB
- 판다스는 기본적으로
multiprocessing
: 특정 데이터를 여러 환경에서 불러올 때- 분산 컴퓨팅 프레임워크: Dask, Vaex 등
- 근데 여기까지 안 가도, pandas 차원에서 사이즈 줄이고, 처리하면서 지우면 메모리 많이 아낄 수 있음
- pandas와 유사한 API
- DB 저장
- 근데 로그 데이터는 보통 db보다 파일 단위로 저장
- ML 기법 사용
- 행렬분해를 통한 차원축소
- 원본 정보 잃어버릴 수 있음
실제 데이터 적용
- 국민건강보험공단_의약품처방정보
- 공공데이터포털에서 가장 큰 데이터
- 2009~2020 모두 다운받으면 31GB
- 청크로 나누어 로드(이걸 일단 파일로 저장하여 메모리 아끼기) -> 다운캐스트 -> parquet로 저장 -> 청크 합치기
- 31GB -> 5GB 정도가 됨
pandas.to_numeric
- downcast 옵션 있음. 맞는 사이즈로 줄여줌
- 큰 데이터 하나보다, 작은 데이터 여러 개가 처리가 빠른 듯
- 1G 정도의 28개 파일 -> 10MB 정도의 409개 파일
- 그래도 여전히 메모리 사용 크다면?
- db처럼 정규화. 컬럼 분리
- 분석(分析)의 사전적 의미는 ‘쪼개는 것’
- 선거처럼 출구조사(표본조사)
- 서브셋을 나눠 합치면 메모리 아낄 수 있음
2. Async state machine
파이썬으로 구현된 분산 시스템에서 시간이 오래 걸리는 작업의 추적 및 상태 관리에 대한 어려움과 이를 해결하기 위한 추상적 아이디어들을 제시합니다. 코드 예시가 있기는 하지만 상세한 파이썬 코드 구현은 없고 고수준으로 추상화된 예시만 나오는 가벼운 발표이니 이 점 염두에 두시기 바랍니다.
- 분산 시스템
- Task 하위에 여러 Subtask
- 어떤 task는 굉장히 오래 걸릴 수 있음
- 병렬 데이터 처리 작업 등에 사용. tast1은 1~50, task2는 51~100 등
- Task Lifecycle
- api serer에서 task의 상태를 여러 status로 정의하여 관리
- Preparing, Running, Terminating, Error, Terminated 등
- 근데 subtask도 비슷하게 상태 관리 로직 필요. substask와 task의 상태 관리 예외 처리 하려면 복잡해짐
- api serer에서 task의 상태를 여러 status로 정의하여 관리
asyncio
예외처리- subtask에 따라서 에러 발생시 상위 task의 상태를 지정하기도 함
- state machine
- 한 번에 하나의 상태만 가지는 머신
- task를 하나의 state machine으로 간주
- state: task의 상태와 해당 상태에서 실행해야 할 함수
- event: 함수의 리턴값
- 분산시스템: CAP Theorem
- 이 중 Partition tolerance는 타협 안하는 요소? 네트워크 문제가 발생해도 시스템 동작. Retry 정책
- Reconciliation loop
- 각 컴포넌트들이 따로 동작하는 게 아니라, 중앙 저장소와 입출력
- k8s도 이런 아키텍처?
- RPC Call에 의한 예외처리가 아님. 그 자리에 DB가 들어옴
3. 로컬 환경에서 사이즈가 큰 데이터를 처리/분석하기 위한 전략: Pandas 2.0, HF Datasets
- 판다스는 메모리를 많이 쓰는 구조
- numpy는 pandas를 위한 구조가 아니어서, pandas로 변환하기 비효율적인 부분 있음
- 싱글 머신을 위해 디자인됨. 분산 환경에 적합하지 않음
pandas 2.0
- 2023.04 발표
- 설치하면 자동으로 적용되며, 기존 버전과의 호환성 좋음
- 메모리 효율성
- 시계열 데이터 성능 향상
- Nullable 데이터 타입. int가 null 있으면 float로 변경되던게 Nullable Int로 됨
- CoW Improvement
- copy on write. 변경과 동시에 쓰기?
- 기존에는 데이터프레임 변경시, 카피본까지 메모리 참조
- cow 개념: 메모리 안정성
- chained assignment
Apache Arrow
- 인메모리 데이터 위한 프레임워크. pandas와 integration 됨
- 판다스에서
dtype="float32[pyarrow]"
와 같이 쓸 수 있음 - string type:
pd.Stringtype()
- numpy 타입에 비해 속도 향상
버전 3개 실험
- 0.24.2 / 2.0.3 / 2.0.3 with
pyarrow
pd.read_csv(파일명, engine='pyarrow')
- pyarrow 없이 하는거는 0.24.2와 큰 차이 없음
- pyarrow 하면 훨씬 빨라짐. 근데 dtype이 변하는 건 아님
- 파일 읽기,쓰기 속도
- csv «« parquet < pickle, feather
- 근데 pickle에서도 pyarrow가 더 빠름
- 다만 pickle은 저장 사이즈가 큼. parquet 추천. Pyspark와도 호환 잘됨(압축률 좋음)
- 실험 1: 행별 연산
- Iteration(
.iterrows
,pd.DataFrame.apply
) vs Vectorization (pd.Series
,np.array
) - 전자보다는 후자가 훨씬 빠름. 전자는 메모리 사용도 많음
- 후자는 어떻게 쓰는거지?
- Iteration(
- 실험 2: 같은 연산 비교
sort_values.head
vsnlargest
- 모든 버전에서 후자가 훨씬 빠름. 메모리 사용도 줄임
- 실험 3: 특정 조건 만족하는 행 select
- 2.0에서 DataFrame.apply 속도가 빨라짐
- df.merge > df.isin »» df.apply > List comprehension
- Method Chaining
- 이전 버전에서는 디버깅 어려운 문제 있었음
- 3.10부터는 행 단위 오류 제공. 가독성이 좋아서 이제는 추천
- cow 개선으로 인해, 가비지 콜렉터도 제공
- 이제는 하나씩 할당하는 것에 비해 속도도 빨라짐. 메모리 사용도 줄임
- 그래도 데이터가 로컬 hdd보다 크다면?
- hugging face 데이터셋
- 이거도 Apache Arrow 포맷. 메모리 제약 없이 불러올 수 있음
4. 반복적인 일이 싫은 선생님의 Python을 활용한 학교에서의 업무자동화 사례
- 현직 수학교사
- 업무자동화 사례 1: 학교생활기록부
- 기록 & 점검하는 업무가 중요
- 독서활동상황 입력 지침: “전체 학년 동안 동일한 책 중복하여 입력지 않음”
- 인쇄된 생기부를 수기로 형광펜으로 중복된 책을 확인하고는 함
- 생기부 담당자는 1,000명의 생기부 검토
- 규칙이 아주 명확하여, 인쇄 대신 csv 파일 전처리하여 리포트 출력
- 책 제목 오타가 있을 수 있음
- 같은 문자열로 인식하는 방법 -> 형태소 분석 라이브러리 사용 (
kiwi
. 한국어 자연어처리 라이브러리) - 수학의 역사(지즈강) vs 수학의 역샤(지즈강): 형태소 분석하여 유사도 계산 가능
list 요소 개수(중복 허용) / set 요소 개수(중복 없음)
비율 계산하여, 중복이 많을수록 유사한 것으로 간주- n권의 책을 2권씩 비교. cutoff 이상인 경우에만 출력
- 같은 문자열로 인식하는 방법 -> 형태소 분석 라이브러리 사용 (
- 업무자동화 사례 2: 원터치 대시보드
- 코로나 시기 온라인 과제 확인. 5개 반 150명의 과제 제출을 확인하고, 미제출시 독려해야 함
- 과제별, 개인별로 클릭 처리해야 함
- 원클릭으로 모든 반 학생들 중 미제출자 확인할 수 없을까?
selenium
,requests
이용하여 로그인 후 시스템 접속- 그래서 미제출자 데이터 모음
- 업무자동화 사례 2: 모둠을 랜덤 편성
- 랜덤 아니더라도, 비슷한 학생들끼리 or 다양한 학생들끼리 편성하려먼 어떻게?
- 적당히 랜덤성 주면서, 학생들 특성 고려한 조편성
- 예시: E 6명, I 6명을 4개 조(3명씩)로 나눔. 한 조당 E/I 1~2명씩 편성
- 가상 데이터:
faker
라이브러리 - 그룹에서 범주별 인원수의 표준편차가 작아지도록 편성
- 이제 동료 선생님에게 코드 전달하거나, 매뉴얼, 프로토타입 제공 등의 요구 생김
- 코드가 있는 건 서로 이해하기 어려움
Streamlit
- 완성하신 웹앱
- 퓨어 파이썬만으로 웹앱 구현 가능 (프론트 경험 전혀 필요x)
print
대신st.write()
쓰면 되고, 마크다운 같이 작성- 파일 업로드하여 처리 가능. seaborn 이용하여 시각화도 가능
- 안정적이진 않음. Django가 더 안정적
5. pandas와 PySpark로 데이터 워크로드 확장하기
- databricks 개발자
- pandas 워크로드를 어떻게 PySpark로 분산처리 하는가?
- pandas는 분산처리가 안됨. 큰 컴퓨터를 쓰거나, 데이터 다운샘플링 하거나, 분산처리 프레임워크로 옮겨야 함(오늘 내용)
- spark 구조
- Driver가 Worker에게 task 명령
- Worker는 하나씩의 Executor 있음. client로부터 받은 task 실행하여 Driver로 리턴
- PySpark는 pandas와 구조가 다름. operation 할 때마다 데이터를 업데이트하는 구조가 아님. 불변성 DataFrame(rdd)
- PySpark: Lazy Execution. pandas: Eager Execution
- 다른점 표 참고(사진)
pandas api on spark
pyspark.pandas = pandas
로 로컬에서 분산처리import pyspark.pandas as pd
하면, 기존 워크로드에서 그대로 분산처리- pyspark.pandas DataFrame -> InternalFrame 거침(인덱스 지정) -> Spark DataFrame
- 단일 노드에서 pandas보다 빠른 성능 (pandas는 싱글 코어)
- 인덱스 종류
- sequence
- pandas의 lazy index와 같이, 순차적으로 1씩 증가함
- 전체 파티션이 단일 노드에서만 처리될 수 있음 -> 큰 데이터는 지양
- distributed-sequence
- 1씩 증가
- group by 방식. 분산처리에 적합
- distributed
- 1씩 증가하지 않으나, 순차적으로 증가x. 임의로 증가
- 파티션별로 인덱스 할당하고, globally 1씩 증가
- 가장 높은 성능
- sequence
- PySpark vs PySpark.pandas
- pandas를 더 큰 데이터로 분산 처리 하고 싶다면, 후자
- PySpark 배우고 싶고, 100% 기능 원한다면 PySpark
pandas udf and function API
- pandas udf: scala udf, python udf와 동일. PySpark column 반환. Series 인풋 Series 아웃풋
- pandas function API: PySpark DataFrame 반환. DataFrame 인풋, DataFrame 아웃풋
- udf: 원하는 결과 형태에 따라 타입 힌트를 줌
- 타입은 pd.Series, int(집계 값) 등
- function API: Vectorization 방식
- oom(out-of-memory) 문제: Salt
- 로컬에서 돌려 보고, Spark에서 돌리는 식으로 사용
- for 루프는 항상 Vectorization(e.g.numpy)을 우선으로 해 보고 생각해야 함. 효율성이 좋지 않음
Spark Connect
- 많은 IDE들이 Spark를 잘 연결하지 못하고 있음. pycharm, jupyter 등
- 언어 지원도 제한적
Spark Connect API
: 응용 프로그램, IDE, 여러 언어를 통합하는 API Layer- DataFrame API, ML API 등 있음?
- IDE에서 사용 가능한지 보기
- 엣지 디바이스에서 jvm 같은거 설치하지 않아도, 클라이언트에서 python만 설치하면 가볍게 Spark 사용 가능. line별로 디버깅도 가능
- 근데 spark는 Lazy Execution으로, 출력 전에 logical plan이 변경될 수 있음. line별 디버깅에 한계가 있어 보임