주제

1. DataFrame 재구성
2. 시계열 제어
3. 데이터 셋에서 시계열 데이터 처리

 

 

DataFrame 재구성

1. 행렬전치 (transpose)

  • 전치행렬 : 행과 열을 교환하여 얻는 행렬. 주 대각선을 축으로 반사 대칭을 한다
  • 데이터의 증가는 행의 방향이 옳다고 생각이 될 때 유용할 것
  • 사용된 데이터는 2017년부터 2021년까지의 한국 프로 야구 팀의 역대 순위
  • 원본 :

원본 데이터의 모습

  • 전치행렬 이후의 모습 :
baseball.transpose()

# 혹은 .T
baseball.T

전치된 모습

 

주의사항

  • 원본은 전치를 두번한 것과 동일하지 않다!
  • 왜? → 전치를 하면 데이터 타입이 변경되기 때문.

원본의 데이터 타입
전치 한번 후의 데이터 타입
두번째 전치 후의 데이터 타입

  • 위와 같이 보통 전치를 하면 모든 데이터 타입이 object로 바뀌기 때문에 원본가 같은 데이터라고 생각하면 안된다!

 

2. 인덱스 레벨 제어

  • stack()
    • 데이터 프레임의 구조를 재조정
    • 컬럼을 로우로 "압축"하는 작업
    • level=
      • 컬럼 축에서 인덱스 축으로 스택할 레벨 지정
    • 아래와 같은 원본 데이터를 스택하면 이런 모습이 된다
data = {
    ('A', 'col1'): [1, 5],
    ('A', 'col2'): [2, 6],
    ('B', 'col1'): [3, 7],
    ('B', 'col2'): [4, 8]
}

df = pd.DataFrame(data)

df.stack()

원본 데이터
재조정된 모습

 

  • unstack()
    • 스택된 것을 되돌림
df.unstack()

 

 

 

3. 재 구조화 (melt)

  • melt()
    • 넒은(wide) 형식의 데이터프레임을 긴(long) 형식으로 재구성
    • id_vars=
      • 식별자 변수로 사용할 열
    • value_vars=
      • 언피벗할 열, 지정하지 않으면 id_vars로 설정되지 않은 모든 열을 사용
    • var_name=
      • 'variable' 열에 사용할 이름을 지정
    • value_name=
      • 'value' 열에 사용할 이름을 지정
    • 예시 :
# 예시 데이터 생성
data = {
    '이름': ['Spencer', 'Lune', 'Mark'],
    '국어': [66, 90, 95],
    '영어': [77, 80, 65],
    '수학': [99, 80, 75]
}

df = pd.DataFrame(data)

df

wide한 데이터

# long형식 데이터프레임 출력
melt_df = df.melt(id_vars='이름', value_vars=['국어', '영어', '수학'], var_name='과목', value_name='점수')
melt_df

long한 데이터로 재구성

 

언피벗이란?

  • 데이터프레임의 구조를 넓은 형식에서 긴 형식으로 변환하는 작업.
  • 측정 변수를 열에서 행 방향으로 이동시킴

 

 

4. 피벗과 피벗테이블 (pivot, pivot_table)

  • pivot()
    • 피벗 테이블을 생성
    • melt와는 반대 기능
    • columns=
      • 피벗 테이블의 열
    • index=
      • 피벗 테이블의 인덱스, 지정하지 않으면 기존의 인덱스 사용
    • values=
      • 피벗 테이블의 값, 지정하지 않으면 모든 열이 사용됨
    • 예시 :
# sample2.csv - 연도별사원성과
company = pd.read_csv('sample2.csv')

company.head()

원본 데이터

company.pivot(index='연도', columns='사원이름', values='연도별매출')

피벗 테이블

 

  • pivot_table()
    • 매개변수를 활용하여 엑셀 스타일의 피벗 테이블을 생성하고 데이터프레임으로 변환
    • values= 
      • 집계할 열
    • index=
      • 인덱스로 사용할 열
    • columns=
      • 그룹화할 열
    • aggfunc= 
      • 집계함수를 지정, 기본값은 mean
    • : "A별 BB의 CCC함수값을 DDDD인덱스로 확인하기"
      • A별 → columns
      • BB별 → values
      • CCC함수값을 → aggfunc
      • DDDD인덱스로 → index
    • 예시 :
# 사원별 누적매출 통계내기
company.pivot_table(values='연도별매출', columns='사원이름', aggfunc='sum')

사원별 누적매출 피벗 테이블

 

 

4. 그룹화 (groupby)

  • groupby()
    • 데이터를 기준을 정하여 그룹화하고 연산을 수행
    • 그룹으로 나눌 열 또는 열들을 선택 후 그룹 객체에 원하는 연산을 수행(집계함수 사용)
  • 예시 :
# 학생 성적 데이터 생성
data = {
    '학생명': ['철수', '영희', '민수', '수현', '지영', '동희'],
    '과목': ['수학', '영어', '수학', '과학', '영어', '과학'],
    '성적': [90, 85, 92, 88, 95, 91]
}

df = pd.DataFrame(data)

df

원본 데이터

# 과목별 평균 성적 계산
subject_mean = df.groupby('과목')['성적'].mean()

pd.DataFrame(subject_mean)

그룹화 결과

  • groupby이후에 agg()를 사용
# gropyby() 이후가 Dataframe은 아니지만 agg()를 사용할 수 있다.
pokemons.groupby('Type 1').agg({'Total': ['max', 'min', 'mean'], 'HP':['max', 'min', 'mean', 'std']}).round(2)

 

 

  • get_group()
    • 그룹화하여 결과를 데이터프레임으로 확인
    • pivot_tabel()보다 수행능력 / 편의성이 뛰어나고, 코드와 데이터의 재사용성이 증가한다.
    • 예시 :
# Type 1중 'Dark'에 해당하는 데이터만 찾기
type1_group.get_group('Dark').head()

조회 결과

 

 

 

 

시계열 제어

1. pd.Timestamp()

  • 날짜 / 시간을 표현하는 데이터
# 인자 입력
t1 = pd.Timestamp(year=2023, month=12, day=20,
            hour=13, minute=23, second=12, microsecond=23411, nanosecond=342)

# 인자 생략 + 세계 협정시 Z
t1 = pd.Timestamp(2023, 12,21,13,45,34,234111).tz_localize('UTC')

# 날짜 표기로 한번에
t1 = pd.Timestamp('2023-12-20T13:32:34.234532498Z')
  • .year, .month등으로 객체 속성에 접근할 수 있다
  • timestamp 사이 사칙연산도 가능하다

 

2. pd.to_datetime()

  • 문자열 또는 숫자를 날짜와 시간으로 변환
  • 인자 입력 방식은 timestamp와 거의 동일
  • 잘못된 형식이나 값이 입력되면 에러가 발생하지 않고, NaN 또는 NaT(Not a Time) 값을 반환
  • DatetimeIndex 객체를 반환
# 날짜 표기법으로 입력
texts = [
    '2020-01-02',
    '2022/01/02',
    '2021.01.02',
    '2023 Jan 02'
]

for t in texts:
    print(pd.to_datetime(t))

 

3.  pd.date_range(start=, end=, periods=, freq=)

  • 날짜 범위를 생성하는 함수
  • 시작일, 종료일, 날짜 간격
# 12월 한 번에 DatetimeIndex만들기
start_date = '2023-12-01'
end_date = '2023-12-31'
index = pd.date_range(start_date, end_date)
index

# 2024.12.31을 마감으로 총 10개의 날짜 만들기
pd.date_range('2024-01-01', '2024-12-31', periods=10)

 

 

5. 날짜 시간 속성 접근자 (dt)

  • 시리즈에서 날짜와 시간과 관련된 속성에 접근할 때 사용
  • 예시 :
dec = pd.date_range('2024-12-01', '2024-12-31', freq='W-MON')
dec

월요일인 주별로 생성

# Series 화
pd.Series(dec)

#데이터프레임 화
dec_df = pd.Series(dec).to_frame('Weeks')
dec_df

# .dt를 통해 속성(Properties) 접근 객체 생성
# 일만 가져오기
dec_df['Weeks'].dt.day

# 달만 가져오기
dec_df['Weeks'].dt.month

일만 가져오기

 

 

데이터 셋에서 시계열 데이터 처리

 

Apple Stock Prices (2015-2020)

Apple Stock Prices for Time series forecasting and Analysis

www.kaggle.com

  • 데이터 생김새

데이터 생김새(누락된 열있음)

  • date를 인덱스로 변경, 데이터 타입이 object임으로 datetime으로 변경
cols = ['date', 'open', 'high', 'low', 'close']

stocks = pd.read_csv('AAPL.csv', usecols=cols, index_col='date')

# 방법 1: to_datetime 사용
stocks.index = pd.to_datetime(stocks.index)
stocks

# 방법 2: read_csv(parse_date=) 인자 사용
stocks = pd.read_csv('AAPL.csv', usecols=cols, index_col='date', parse_dates=['date'])
stocks

 

  • 요일 열 추가
days = stocks.index.day_name()
stocks.insert(0, '요일' ,days)

 

  • 날짜 포맷 정리
    • strftime() : 날짜 타입의 포맷을 변경
stocks['date'].dt.strftime('%Y-%m-%d %H:%M:%S')

 

 

  • 시계열 조회
# 년월일 .loc['label']
stocks.loc['2015-05-27']

# .loc[['label1', 'label2']]
stocks.loc[['2015-05-27', '2015-06-01']]

# 슬라이싱 1
stocks.loc['2015-05-27':'2015-06-01']

# 슬라이싱 2
stocks.loc[:'2015-06-01']

# 년월만 탐색
stocks.loc['2015.05']

# 년월 슬라이싱
stocks.loc['2015.05':'2015.07']

# 년 조회
stocks.loc['2015':'2016']

 

 

 

재색인(reindex)

  • 인덱스를 새로운 인덱스로 변경하거나 재정렬
  • 시리즈, 데이터 프레임 모두 가능
  • 데이터를 새로운 인덱스에 맞게 재배열하거나 누락된 값을 처리하는 데 유용함
  • 예시 :
# 기존 Series 생성
series = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
series

# 새로운 인덱스로 재정렬
new_index = ['c', 'b', 'a', 'd']
new_series = series.reindex(new_index)
new_series

  • 애플 데이터셋에는 주말이 없다 → 주말을 추가해보자
# 가장 과거 날짜
min_date = stocks.index.min()
min_date

# 가장 최근 날짜
max_date =  stocks.index.max()
max_date

# 비어있는 날짜까지 데이터 생성
new_index = pd.date_range(start=min_date, end=max_date, freq='D')
new_index

new_index.day_name().value_counts()

주말 생성

# 새로운 인덱스로 재색인
stocks.reindex(new_index)

# .fillna()로 채우거나, fill_value=로 채우거나
stocks_new1 = stocks.reindex(new_index, fill_value='휴장')
stocks_new1

주말은 휴장으로 채워진 모습

 

 

 

재샘플링(resample)

  • 시계열 데이터의 주기를 변경
  • 다운 샘플링 : 데이터 빈도를 더 낮은 주기로 설정
  • 업 샘플링 : 데이터 빈도를 더 높은 주기로 설정(월별로 주어진 데이터를 일별, 시간별 등 더 높은 주기로 채움)
  • 다운 샘플링 예시 :
# 데이터 생성
data = {'value': [10, 20, 30, 40, 50]}
index = pd.date_range('2021-01-01', periods=5, freq='D')
df = pd.DataFrame(data, index=index)
df

# 주간 평균으로 다운샘플링
weekly_df = df.resample('W').mean()
weekly_df

다운 샘플링

  • 업 샘플링 예시 :
    • 업샘플링 시에는 보간(interpolation)을 통해 데이터를 채워주어야 한다
    • 보간 방식은 method=로 지정
# 원본 데이터 생성
data = {'value': [10, 20]}
index = pd.to_datetime(['2021-01-01', '2021-02-01'])
df = pd.DataFrame(data, index=index)
df

  • 보간(interpolation) :
    • 주어진 데이터 사이에 누락값을 추정하는 방법
    • 선형 보간, 최근접 보간, 이웃 보간 등
  • .asfreq()
    • 업샘플링 시 사용되는 함수
    • 주어진 주기에 맞게 데이터를 새로운 인덱스로 재구성
    • 누락된 데이터를 NaN 값으로 채움
  • .interpolate()
    • 보간을 수행
# 일별로 업샘플링하고 선형 보간으로 데이터 채우기
daily_df = df.resample('D').asfreq().interpolate()
daily_df

일별로 데이터 업 샘플링

 

 

 

 


느낀점

 

오늘 수업이 가장 힘들었던 것 같다..시계열 부분은 sql할 때도 헷갈리는 게 많아서 좋아하지 않았는데 여기서도 마찬가지로 인자가 너무 많아서 집중이 어려웠다. 다음에 써 볼 기회가 생기면 그때 다시 찾아보면서 공부해야겠다. 그래도 이번주 수업을 들으면서 판다스에 대한 자심감이 많이 생긴 것 같다.

+ Recent posts