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

파이썬- 숫자로 구성된 데이터의 포맷변환하기

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

데이터를 가공하다 보면 원천데이터가 다양하게 나눠져 있어서 일관되게 포맷을 맞추기 위한 가공작업을 빈번하게 해야 합니다.

 

요즘 AI 코딩시대여서 모르면 AI에게 물어보면 쉽게 해결되지만, 매번 비슷한 질문을 물어보기 귀찮은 것도 사실입니다.

프롬프트를 구체적으로 작성하지 않으면 제대로된 답을 주지 않기 때문에 프롬프트 작성하는데 시간이 많이 걸리기도 합니다.

 

내가 다루는 데이터의 특성에 따라 몇가지 패턴만 알면 좀 더 빨리 해결할 수 있으므로 자주 마주하게되는 패턴을 정리하고자 합니다.

 

1.  카드번호 변환

카드번호 저장 형태는 다양합니다. 숫자만 저장하기도 하고, 숫자 4개씩 나눠서 '-' 하이픈으로 연결하여 저장하기도 합니다.

데이터 저장할 때는 숫자만 저장하는 것이 편하지만 화면에 표출할 때는 4자리씩 나눠서 표시하는 것이 보기 편합니다.

이에 따른 변환작업이 빈번하게 일어나는데 내가 이전에 작성한 코드 어딘가에 있으나 막상 찾으려 하면 쉽게 찾기 어렵습니다.

따라서 블로그에 정리해 놓고 찾아보기로 하였습니다.

 

pandas 데이터프레임에서 16자리 숫자 문자열을 "1234-1234-1234-1234" 형태로 포맷하려면 str.replace() 또는 str.extractall() 대신, 정규식 그룹핑과 str.replace() 또는 슬라이싱을 사용할 수 있습니다.


✅ 방법 1: 정규표현식으로 포맷하기 (가장 직관적)

df['card_no'] = df['card_no'].str.replace(r'(\d{4})(?=\d)', r'\1-', regex=True)

이 방식은 4자리마다 하이픈을 추가하고, 마지막에는 붙이지 않습니다.


✅ 방법 2: 슬라이싱을 이용한 포맷 (명확하게 제어)

df['card_no'] = df['card_no'].apply(lambda x: f"{x[:4]}-{x[4:8]}-{x[8:12]}-{x[12:]}")

💡 예제 전체 코드

import pandas as pd

df = pd.DataFrame({
    'card_no': ['1234123412341234', '5678567856785678']
})

# 방법 1: 정규식 사용
df['card_no_format'] = df['card_no'].str.replace(r'(\d{4})(?=\d)', r'\1-', regex=True)

# 방법 2: 슬라이싱 사용
df['card_no_format2'] = df['card_no'].apply(lambda x: f"{x[:4]}-{x[4:8]}-{x[8:12]}-{x[12:]}")

print(df)

✅ 출력 예시

          card_no     card_no_format   card_no_format2
0  1234123412341234  1234-1234-1234-1234  1234-1234-1234-1234
1  5678567856785678  5678-5678-5678-5678  5678-5678-5678-5678

둘 중 편한 방식으로 사용하시면 됩니다. apply() 방식은 문자열 길이가 16자리로 고정된 경우 확실하고 명시적입니다.

 

[예외사항]

데이터가 일부 빠진 경우 위의 케이스로는 에러가 발생됩니다. 즉, NaN, Null 값이 있을 때 적용할 수 있는 방법입니다.

 

데이터 필드에 빈 값(None, NaN, '') 이 있을 수 있는 상황을 고려해서 처리하는 안전한 방식은 다음과 같습니다:


✅ 방법 1: apply() 사용 + 예외 처리 추가

df['card_no'] = df['card_no'].apply(
    lambda x: f"{x[:4]}-{x[4:8]}-{x[8:12]}-{x[12:]}" if pd.notnull(x) and len(str(x)) == 16 else x
)

✅ 방법 2: 정규식 방식 + 빈 값 예외처리

df['card_no'] = df['card_no'].apply(
    lambda x: re.sub(r'(\d{4})(?=\d)', r'\1-', x) if pd.notnull(x) and len(str(x)) == 16 else x
)

이 방법은 import re 필요합니다.


🔎 전체 예제

import pandas as pd
import re

df = pd.DataFrame({
    'card_no': ['1234123412341234', None, '5678567856785678', '', '12345678']
})

df['card_no_fmt'] = df['card_no'].apply(
    lambda x: f"{x[:4]}-{x[4:8]}-{x[8:12]}-{x[12:]}" if pd.notnull(x) and len(str(x)) == 16 else x
)

print(df)

✅ 결과

          card_no        card_no_fmt
0  1234123412341234  1234-1234-1234-1234
1             None               None
2  5678567856785678  5678-5678-5678-5678
3                             (빈 문자열)
4       12345678        12345678

💡 참고

  • pd.notnull(x) → None, NaN 값 필터링
  • len(str(x)) == 16 → 정확히 16자리인 경우만 포맷
  • 조건에 해당하지 않으면 기존 값 유지

필요시 특정 조건에 따라 'Invalid' 또는 '' 등으로 대체도 가능합니다.

  

2.  날짜 데이터를 연-월로 변경

데이터중 가장 다루기 어려우면서 다룰 일이 많은 데이터가 날짜 이다.

텍스트로 된 것을 날짜 타입으로 변경하거나, 날짜 계산하거나, 포맷을 변경하는 등 날짜와 시간을 변환하는 일이 참 많습니다.

 

여기서는 '2025-08-01' 같이 날짜를 '2025년 8월' 같이 연도-월로 변경 표기하는 방법입니다. 

데이터를 가공해서 pivot_table 을 만들 때 월별 통계를 만들기 위해 사전에 연-월 데이터 변경이 필요합니다.

이럴 때 필요한 방법입니다.

 

날짜가 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')이 더 좋습니다.

반응형