본문 바로가기
파이썬(Python)

파이썬-날짜데이터 포맷 변경하기

by 즐거운코딩 2025. 8. 13.
반응형

데이터항목중에 가장 까다로운 처리가 날짜 데이터 입니다.

다양한 형태의 변환으로 데이터 분석에 활용도가 높아 빅데이터분석기사와 같은 실기시험에서도 비중이 높아지고 있다고 합니다.

 

그만큼 다양한 변환 작업이 있는데 제가 실무에서 마주쳤던 케이스에 대해 몇가지 예를 들어 설명하겠습니다.

 

1.  날짜데이터에서 연도-월 추출하기

가장 기본적이면서 많이 사용하는 것으로 pivot이나 groupby 통계데이터를 월별로 만들때 필요합니다.

 

가.  날짜 데이터를 한글의 연-월 로 표기

청구일이 datetime 형식으로 되어 있다면, 청구월 필드를 다음과 같이 생성할 수 있습니다:


✅ 방법: dt.strftime() 사용

df['청구월'] = df['청구일'].dt.strftime('%Y년 %-m월')
  • %Y → 4자리 연도
  • %-m → 0을 생략한 월 (예: 6월, 11월)
    • Windows 환경에서는 %-m이 안 될 수 있어 df['청구일'].dt.month로 처리 가능

✅ Windows 호환 버전

Windows 환경에서는 %-m이 동작하지 않으므로 다음처럼 처리하세요:

df['청구월'] = df['청구일'].dt.year.astype(str) + '년 ' + df['청구일'].dt.month.astype(str) + '월'

✅ 예시

import pandas as pd

# 예시 데이터프레임
df = pd.DataFrame({
    '청구일': pd.to_datetime(['2025-06-01', '2025-07-15'])
})

# 청구월 필드 생성
df['청구월'] = df['청구일'].dt.year.astype(str) + '년 ' + df['청구일'].dt.month.astype(str) + '월'

print(df)

🧾 결과

         청구일     청구월
0  2025-06-01  2025년 6월
1  2025-07-15  2025년 7월

필요 시 청구일이 문자열인 경우 먼저 pd.to_datetime()으로 변환 후 위 방법을 적용하세요.

 

[참고사항]

 

 **월에 항상 두 자리 숫자(예: 01, 02, ..., 12)**로 표시되도록 하려면 .zfill(2) 또는 str.zfill()을 사용하면 됩니다.


✅ 수정된 코드 (앞에 0 붙이기)

df['청구월'] = (
    df['청구일'].dt.year.astype(str) + '년 ' +
    df['청구일'].dt.month.astype(str).str.zfill(2) + '월'
)

✅ 예시 실행

import pandas as pd

# 예제 데이터
df = pd.DataFrame({
    '청구일': pd.to_datetime(['2025-01-01', '2025-06-15', '2025-11-30'])
})

# 청구월 생성 (월을 두 자리로 표시)
df['청구월'] = (
    df['청구일'].dt.year.astype(str) + '년 ' +
    df['청구일'].dt.month.astype(str).str.zfill(2) + '월'
)

print(df)

🧾 출력 결과

         청구일       청구월
0  2025-01-01  2025년 01월
1  2025-06-15  2025년 06월
2  2025-11-30  2025년 11월

필요에 따라 '년', '월' 사이에 공백을 조정할 수 있습니다.

 

나.  연도-월을 숫자로 변환

datetime 타입의 날짜에서 연월(YYYY-MM) 정보만 추출하여 새로운 필드에 저장하려면 pandas의 .dt 접근자를 이용해 다음과 같이 처리할 수 있습니다.


✅ 방법: .dt.to_period('M') 또는 .dt.strftime('%Y-%m')

1. to_period('M') 사용 (권장: 실제 기간 타입으로 저장됨)

df['연월'] = df['날짜컬럼'].dt.to_period('M')
  • 결과: Period 타입으로 2025-01 형식 저장
  • 장점: 기간 비교/필터링 등에서 유리함

2. strftime('%Y-%m') 사용 (문자열로 저장됨)

df['연월'] = df['날짜컬럼'].dt.strftime('%Y-%m')
  • 결과: 문자열 '2025-01'
  • 장점: 화면 표시 목적이나 CSV 저장 시 깔끔

예제

import pandas as pd

# 예시 데이터프레임
df = pd.DataFrame({
    '날짜': pd.to_datetime(['2025-01-01 10:00:00', '2025-02-15 14:30:00'])
})

# 연월 컬럼 추가
df['연월'] = df['날짜'].dt.strftime('%Y-%m')  # 또는 .dt.to_period('M')

print(df)

출력:

                  날짜      연월
0 2025-01-01 10:00:00  2025-01
1 2025-02-15 14:30:00  2025-02

원하는 데이터 유형(문자열 vs 기간형)에 따라 두 방법 중 하나 선택하시면 됩니다.
분석/그룹핑이 목적이면 to_period('M'), 저장/표시가 목적이면 strftime('%Y-%m')이 더 좋습니다.

 

반응형

2.  날짜 데이터의 주간 데이터 변환

회사 주간보고서 작성시 주간 단위로 데이터를 구분하여 통계 작업을 할 일이 빈번합니다.

주간의 기준도 보고 요일에 맞춰서 월 ~ 일 또는 수 ~ 화 등 다양하게 만들어야 하는 상황이 있습니다.

 

아래 예시를 참고로 일데이터를 주간 단위로 구분하는 방법입니다.

 

가.  주간 단위 구분하기

조회 기간이 start_date ~ today 로 주어졌다고 가정하고, 이 기간 내의 날짜들을 화요일 ~ 다음 주 수요일 (미포함) 기준으로 연속적인 주차(1W, 2W, 3W...) 로 Week_no 를 부여하는 방식입니다.


✅ 핵심 로직

  • start_date ~ today 까지 범위 내에서 화요일 시작 ~ 다음 수요일 미포함 단위로 구간을 나눔
  • 각 날짜가 어떤 주차 구간에 속하는지 계산하여 Week_no 부여 (1W, 2W, ...)

✅ 수정된 코드

import pandas as pd
from datetime import datetime, timedelta

# 예시 데이터
data = {
    'TRVL_DATE': [
        '2025-05-21', '2025-05-28', '2025-06-01',
        '2025-06-03', '2025-06-04', '2025-06-07'
    ],
    'TRVL_COUNT': [1000, 1200, 43444, 56739, 133551, 57114],
    'CAR_COUNT': [800, 850, 8195, 9896, 20096, 9868]
}
df = pd.DataFrame(data)
df['TRVL_DATE'] = pd.to_datetime(df['TRVL_DATE'])

# 기준 날짜 설정
start_date = pd.to_datetime("2025-05-20")
end_date = datetime.today().normalize()  # 오늘 날짜
# end_date = pd.to_datetime("2025-06-10")  # 예: 특정 날짜로 고정할 수도 있음

# 첫 화요일 찾기 (start_date 포함 또는 그 이후)
def get_first_tuesday(date):
    weekday = date.weekday()
    days_until_tuesday = (1 - weekday) % 7
    return date + timedelta(days=days_until_tuesday)

# 첫 주 시작일 기준으로 주차 범위 생성
first_tuesday = get_first_tuesday(start_date)
date_ranges = []
week = 1
current_start = first_tuesday
while current_start < end_date:
    current_end = current_start + timedelta(days=8)  # 다음 수요일
    date_ranges.append((current_start, current_end, f'{week}W'))
    current_start = current_start + timedelta(days=7)
    week += 1

# 주차 부여 함수
def get_week_no(date):
    for start, end, label in date_ranges:
        if start <= date < end:
            return label
    return None

df['Week_no'] = df['TRVL_DATE'].apply(get_week_no)
df['요일'] = df['TRVL_DATE'].dt.day_name()

# 결과 출력
print(df[['TRVL_DATE', '요일', 'TRVL_COUNT', 'CAR_COUNT', 'Week_no']])

✅ 출력 예 (예상)

TRVL_DATE 요일 TRVL_COUNT CAR_COUNT Week_no

2025-05-21 Wednesday 1000 800 1W
2025-05-28 Wednesday 1200 850 2W
2025-06-01 Sunday 43444 8195 2W
2025-06-03 Tuesday 56739 9896 3W
2025-06-04 Wednesday 133551 20096 3W
2025-06-07 Saturday 57114 9868 3W

✅ 커스터마이징 팁

  • 요일 시작 기준을 변경하려면 get_first_tuesday()의 1 값을 바꾸세요 (0=월, 1=화, ..., 6=일)
  • 주차 이름 접두사 ('1W') 도 'Week 1' 등 자유롭게 수정 가능

 

나.  기간 필드 추가하기

 

주어진 데이터에서 각 WEEK_NO별  시작일(TRVL_DATE 최소값)종료일(TRVL_DATE 최대값) 을 기준으로 기간 필드(기간) 를 구성하는 DataFrame을 만들려면 아래와 같이 처리하면 됩니다:


✅ 코드 예시

import pandas as pd

# 주어진 데이터프레임이 있다고 가정 (예: df)
# TRVL_DATE는 datetime 타입이라고 가정
# df = pd.read_csv(...) 또는 기존 데이터 그대로 사용

# 1. WEEK_NO 기준으로 시작일, 종료일 집계
week_period_df = df.groupby('WEEK_NO').agg(
    시작일=('TRVL_DATE', 'min'),
    종료일=('TRVL_DATE', 'max')
).reset_index()

# 2. 날짜 형식 변경 및 '기간' 필드 생성
week_period_df['기간'] = week_period_df['시작일'].dt.strftime('%m/%d') + ' ~ ' + week_period_df['종료일'].dt.strftime('%-m/%-d')
# ⚠ Windows에서는 %-m 대신 %#m 사용

# 3. 원하는 컬럼 순서로 정리
week_period_df = week_period_df[['WEEK_NO', '기간', '시작일', '종료일']]

print(week_period_df)

✅ 출력 예시 (예상 결과)

WEEK_NO 기간 시작일 종료일

1W 05/06 ~ 5/13 2025-05-06 2025-05-13
2W 05/14 ~ 5/20 2025-05-14 2025-05-20
3W 05/21 ~ 5/27 2025-05-21 2025-05-27

✅ 참고

  • strftime('%m/%d'): 앞에 0 붙음 → 예: 05/06
  • strftime('%-m/%-d'): 0 없이 → 예: 5/6 (macOS/Linux)
  • strftime('%#m/%#d'): Windows에서 사용

다.  전주 대비 데이터 차이 필드 추가하기

전주 대비 오류율 변화량을 계산하여 새로운 컬럼(예: '전주대비_오류율_차이')을 추가하려면 pandas.Series.diff() 를 사용하면 간단합니다.


✅ 예제 코드

import pandas as pd

# 예시 데이터프레임
df = pd.DataFrame({
    '주차': ['1W', '2W', '3W', '4W', '5W', '6W', '7W', '8W'],
    '이상주행': [7410, 6363, 7209, 6065, 6217, 7334, 9564, 6939],
    '총주행': [814005, 783122, 784765, 702137, 692036, 778265, 769003, 639443],
    '오류율': [0.9103, 0.8125, 0.9186, 0.8638, 0.8984, 0.9424, 1.2437, 1.0852]
})

# 전주 대비 오류율 차이 계산
df['전주대비_오류율_차이'] = df['오류율'].diff()

print(df)

✅ 결과 예시 (소수점 반올림 포함)

주차 오류율 전주대비_오류율_차이

1W 0.9103 NaN
2W 0.8125 -0.0978
3W 0.9186 +0.1061
4W 0.8638 -0.0548
5W 0.8984 +0.0346
6W 0.9424 +0.0440
7W 1.2437 +0.3013
8W 1.0852 -0.1585

✅ .diff()는 기본적으로 이전 행과의 차이를 계산합니다
✅ 첫 번째 주차는 비교 대상이 없으므로 NaN


🔧 추가 옵션

  • 반올림: df['전주대비_오류율_차이'].round(4)
  • 증감 여부 판단도 추가 가능

 

👉  참고사항

 

오류 처리

'Timestamp' object has no attribute 'dt'

✅ 원인

.dt는 pandas Series 전체에 적용할 때만 사용 가능합니다.
Timestamp는 단일 값이므로 .dt를 사용할 수 없습니다.


✅ 해결 방법

단일 값 (Timestamp)일 경우

# 단일 값
timestamp = pd.Timestamp('2025-06-11 14:23:00')

# 날짜만 추출 (datetime.date 타입)
date_only = timestamp.date()

print(date_only)  # 출력: 2025-06-11

Series (데이터프레임 열)일 경우

df['날짜'] = df['datetime컬럼'].dt.date

✅ 예시: 언제 .dt vs .date() 사용?

데이터 방법 설명

Series (df['col']) df['col'].dt.date 여러 행에 대해 적용
Timestamp (단일값) ts.date() 개별 값에 대해 적용

✅ 정리

  • df['컬럼'].dt.date → ✅ OK (Series)
  • Timestamp.date() → ✅ OK (단일 값)
  • Timestamp.dt.date → ❌ 오류 발생
데이터프레임 열의 날짜 타입이 datetime 으로 연월일시로 되어 있는데 연월일 데이터만 추출하는 방법 

 

데이터프레임의 datetime 컬럼에서 연-월-일(YYYY-MM-DD) 정보만 추출하려면 다음 방법을 사용할 수 있습니다:


✅ 방법 1: .dt.date 사용 (Python의 date 객체로 반환)

df['날짜_연월일'] = df['datetime컬럼'].dt.date
  • 예: 2025-06-10 14:23:00 → 2025-06-10 (date 타입)

✅ 방법 2: .dt.strftime('%Y-%m-%d') 사용 (문자열로 반환)

df['날짜_연월일'] = df['datetime컬럼'].dt.strftime('%Y-%m-%d')
  • 예: 2025-06-10 14:23:00 → '2025-06-10' (string)

✅ 어떤 방식이 더 좋을까?

  • 날짜 계산 등 연산을 해야 할 경우: .dt.date
  • 표시용(시각화, CSV 저장 등): .dt.strftime('%Y-%m-%d')

🔍 예제 전체 코드

import pandas as pd

df = pd.DataFrame({
    'datetime컬럼': pd.to_datetime([
        '2025-06-10 14:23:00',
        '2025-06-11 09:00:00'
    ])
})

df['날짜_연월일'] = df['datetime컬럼'].dt.date
# 또는 문자열로: df['날짜_연월일'] = df['datetime컬럼'].dt.strftime('%Y-%m-%d')

print(df)

 

 

반응형