주제
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

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

※ 언피벗이란?
- 데이터프레임의 구조를 넓은 형식에서 긴 형식으로 변환하는 작업.
- 측정 변수를 열에서 행 방향으로 이동시킴
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

데이터 셋에서 시계열 데이터 처리
- 사용한 데이터 셋 : 애플의 2015년부터 2020년도까지의 주식 변화
- https://www.kaggle.com/datasets/suyashlakhani/apple-stock-prices-20152020
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할 때도 헷갈리는 게 많아서 좋아하지 않았는데 여기서도 마찬가지로 인자가 너무 많아서 집중이 어려웠다. 다음에 써 볼 기회가 생기면 그때 다시 찾아보면서 공부해야겠다. 그래도 이번주 수업을 들으면서 판다스에 대한 자심감이 많이 생긴 것 같다.
'Data Science > TIL (Today I Learned)' 카테고리의 다른 글
| 프로그래머스 데이터분석 데브코스 1기 - 32일차 (1) | 2024.01.09 |
|---|---|
| 프로그래머스 데이터분석 데브코스 1기 - 31일차 (1) | 2024.01.08 |
| 프로그래머스 데이터분석 데브코스 1기 - 29일차 (1) | 2024.01.04 |
| 프로그래머스 데이터분석 데브코스 1기 - 28일차 (0) | 2024.01.03 |
| 프로그래머스 데이터분석 데브코스 1기 - 27일차 (1) | 2024.01.02 |