데이터 분석 입문

Chapter.2 데이터 분석 입문(2)

devjjun 2026. 3. 26. 20:57

TIL(Today I Learned)


1️⃣데이터 분석 입문 2

데이터 타입 변환(astype)

astype() : 데이터에 '결측치'나 '특수문자'가 없을 때 사용

df['시료번호'] = df['시료번호'].astype(int)    # 문자 -> 정수형으로
df['측정값'] = df['측정값'].astype(float)    # 문자 -> 실수형으로

df.dtypes

 

pd.to_numeric() : 데이터에 'N/A', '미측정', '점검중' 같은 문자가 섞여있을 때 사용

df_messy['검사결과_숫자'] = pd.to_numeric(df_messy['검사결과'], errors='coerce')

print(df_messy)
# '불량' -> NaN 으로 안전하게 변환됩니다.

 

실습 : 결측치를 특정 값으로 채우는 방법

df_messy['검사결과_변경'] = df_messy['검사결과_숫자'].fillna('Fail')
print(df_messy)

 

날짜와 시간 다루기(datetime)

날짜 변환: pd.to_datetime()

# format='mixed': 형식이 뒤죽박죽 섞여 있어도 알아서 변환
# errors="coerce" : 날짜로 변환 불가능한 텍스트를 결측치(NaT)처리
df["날짜_new"] = pd.to_datetime(df["날짜"], format="mixed", errors="coerce")
df["날짜_new"].dtype # datetime64[ns] 확인

 

날짜 정보 추출 (.dt접근자)

df.dt.year 연도 추출 2023
df.dt.month 월 추출 3
df.dt.day 일 추출 7
df.dt.day_name() 요일 이름 추출 Tuesday
# 필요한 정보만 새 컬럼으로 만들기
df['연도'] = df['날짜_new'].dt.year
df['월'] = df['날짜_new'].dt.month
df['요일'] = df['날짜_new'].dt.day_name()

df[['날짜_new', '연도', '월', '요일']]

 

날짜 연산 (Time Delta)

from datetime import datetime

# 현재 시간 생성
now = datetime.now()

# 경과일수 계산 (현재 - 검사일)
df['경과일수'] = now - df['날짜_new']

# 일수만 숫자로 뽑고 싶을 때
df['경과일수_숫자'] = df['경과일수'].dt.days

 

포맷 코드와 문자열 변환 (strftime,strptime)

  • 주요 포맷 코드:
    • %Y : 4자리 연도 (2025)
    • %y : 2자리 연도 (25)
    • %m : 월 (01 ~ 12)
    • %B : 월의 전체 이름 (January, February)
    • %d : 일 (01 ~ 31)
    • %H:%M:%S : 시, 분, 초 (14:30:15)
  • strftime(String From Time): 날짜 객체 → 문자열 (출력용)
from datetime import datetime

# 1. 현재 시간 가져오기
now = datetime.now()

# 2. 다양한 포맷으로 변환 (String From Time)
report_date = now.strftime("%Y-%m-%d")           # 2026-03-24
full_time = now.strftime("%Y-%m-%d %H:%M:%S")    # 2026-03-24 20:48:30
kr_format = now.strftime("%Y년 %m월 %d일")       # 2026년 03월 24일
  • strptime(String Parse Time): 문자열 → 날짜 객체 (분석용)
from datetime import datetime

# 1. 텍스트 형태의 날짜 데이터
date_str = "2026-03-24 15:30:00"

# 2. 문자열의 형식을 그대로 맞춰서 해석 (String Parse Time)
# 주의: 원본 문자열의 구분자(-, :, 공백)와 포맷 코드가 완벽히 일치해야 합니다!
date_obj = datetime.strptime(date_str, "%Y-%m-%d %H:%M:%S")

print(f"변환된 객체: {date_obj}")
print(f"타입 확인: {type(date_obj)}") # <class 'datetime.datetime'>

 

데이터 정제 및 변환 (Cleaning&Transformation)

중복 확인 (duplicated)

# 중복된 행인지 확인 (True/False 반환)
# 기본적으로 처음 나온 건 False, 그 뒤에 나온 똑같은 건 True
df.duplicated()

# 중복된 데이터만 눈으로 확인하기
df[df.duplicated()] # df[조건]

 

중복 제거 (drop_duplicates)

# 1. 완전 중복 제거 (모든 컬럼의 값이 같아야 제거)
df_clean = df.drop_duplicates()
# 2. 특정 컬럼 기준 제거 (subset)
# "이름이 같으면 중복으로 치자!" (가장 첫 번째 데이터만 남김 - keep='first')
df_unique_user = df.drop_duplicates(subset=['이름'])
# 3. 마지막 데이터 남기기 (keep='last')
# "이름이 같으면 가장 최근(마지막) 데이터만 남기자!"
df_last = df.drop_duplicates(subset=['이름'], keep='last')

 

데이터 변환의 함수:mapvsapply

  • map(): 주로Series(하나의 컬럼)에 적용하며, 딕셔너리({키: 값})를 사용해 값을 1:1로 갈아 끼울 때 가장 빠르고 효율적
# 검사 결과 코드 변환
df_qa = pd.DataFrame({'검사ID': ['T01', 'T02', 'T03'],'결과코드': [0, 1, 0]})

# 0은 '합격', 1은 '불량'으로 매핑
result_map = {0: '합격', 1: '불량'}
df_qa['판정'] = df_qa['결과코드'].map(result_map)
  • apply(): map으로 처리하기 힘든 복잡한 조건문(if-else)이나 사용자 정의 함수(def)를 적용할 때는apply를 사용
# 측정 온도에 따라 상태 분류
def check_temp(temp):
	if temp > 80:
        return '과열'
    elif temp > 40:
        return '정상'
    else:
        return '저온'

df_sensor = pd.DataFrame({'온도': [25, 55, 85]})
df_sensor['상태'] = df_sensor['온도'].apply(check_temp)

df_sensor

 

📌map은 한 번에 한 컬럼만 보지만,apply(axis=1)을 쓰면 ‘행 전체(여러 컬럼)’를 보면서 계산할 수 있습니다.

axis에 따른 반환값

정렬하기 (sort)

값 기준 정렬 (sort_values)

# 상황 1: 불량수가 많은 공정부터 확인 (내림차순 정렬)
df_high_defect = df_qa.sort_values(by="불량수", ascending=False) #True(기본값): 오름차순, False: 내림차순

 

인덱스 기준 정렬 (sort_index)

# 위에서 정렬되어 뒤섞인 데이터프레임 (df_priority)
# 다시 인덱스 0, 1, 2... 순으로 되돌리기
df_restored = df_priority.sort_index()

 

데이터 합치기 (concat&merge)

Concat (블록 쌓기): 레고 블록을 위나 옆으로 붙이듯 연결

# 두 가지 데이터를 하나로 합치기 (위아래 연결)
total_data = pd.concat([df_d1, df_d2], axis=0, ignore_index=True) #axis=0: 위/아래, axis=0: 양 옆

 

Merge (관계형 병합):merge는 양쪽 데이터의 공통된 열(Key)을 찾아 논리적으로 연결하는 방식입니다.

Inner "교집합" - 양쪽 모두에 데이터가 있는 경우만 합침 완벽한 데이터만 남음 (가장 깔끔함)
Left "왼쪽 우선" - 왼쪽 데이터는 다 살리고, 오른쪽은 정보가 있을 때만 가져옴 실무에서 가장 많이 사용!
Right "오른쪽 우선" - 오른쪽 데이터는 다 살리고, 왼쪽은 정보가 있을 때만 가져옴 Left와 방향만 반대
Outer "합집합" - 양쪽 데이터 중 하나라도 있으면 다 가져옴 모든 정보를 잃지 않고 싶을 때 사용

 

# --- (1) Inner Join: 양쪽에 모두 있는 부분만 합쳐짐 ---
inner_merge = pd.merge(df_d1, df_d2, on='컬럼명', how='inner')

 

데이터 통계 요약 (Aggregating)

# 전체 제품의 평균 두께는?
avg_thickness = df ["두께"].mean()
# min, max, median, mean 등 다양한 값 도출 가능

 

📌사용자 정의 요약

# 두께는 최소/최대/중앙값을, 강도는 최소/최대/평균을 확인
def my_range(x):
    return x.max() - x.min()

custom_agg = df.agg({
    "두께": ["min", "max", "median"],
    "강도": ["min", "max", "mean", my_range]
})

 

그룹별 집계 (groupby)

  • df.groupby("컬럼")[""].집계함수
  • df.groupby("컬럼")[""].agg()
  • 집계함수 종류:
    • mean : 평균, median : 중앙값, sum : 합계 , count : 갯수, min : 최소, max : 최대
# --- 여러 통계량 한 번에 보기 (.agg) ---
# 라인별로 생산량의 합계와 불량수의 평균을 동시에 확인합니다.
line_summary = df_factory.groupby("라인").agg({
    '생산량': 'sum',
    '불량수': 'mean'
})
line_summary

 

Transform (변환) : df.groupby("컬럼")["값"].transform()

# --- 라인별 평균 생산량을 계산해서 새 컬럼으로 붙이기 ---
# transform('mean')을 쓰면 A라인 행에는 A평균이, B라인 행에는 B평균이 들어갑니다.
df_factory["라인평균생산량"] = df_factory.groupby("라인")["생산량"].transform("mean")

 

2️⃣Python 알고리즘 주요 문제 

문제1

  • 문제 설명: 어떤 문장의 각 알파벳을 일정한 거리만큼 밀어서 다른 알파벳으로 바꾸는 암호화 방식을 시저 암호라고 합니다. 예를 들어 "AB"는 1만큼 밀면 "BC"가 되고, 3만큼 밀면 "DE"가 됩니다. "z"는 1만큼 밀면 "a"가 됩니다. 문자열 s와 거리 n을 입력받아 s를 n만큼 민 암호문을 만드는 함수, solution을 완성해 보세요.
  • 제한 사항
    • 공백은 아무리 밀어도 공백
    • s는 알파벳 소문자, 대문자, 공백으로만 구성
    • s의 길이는 8000이하
    • n은 1이상, 25이하인 자연수
  • 입출력 예

  • 문제 접근: s를 구성하는 문자 c의 대소문자 여부에 따라 유니코드 형태로 바꾼 수를 알파벳의 갯수인 26으로 나눈 나머지를 구한 뒤 대문자A의 유니코드를 더해 다시 문자형태로 만들어 문자열을 구성하면 될 것 같다.
  • 코드
def solution(s, n):
    answer = ''
    for c in s:
        num = 0
        if c.isupper():
            num = ord(c) - ord('A')
            num = (num+n)%26
            num = num + ord('A')
            answer += chr(num)
        elif c.islower():
            num = ord(c) - ord('a')
            num = (num+n)%26
            num = num + ord('a')
            answer += chr(num)
        else:
            answer += " "
    return answer

💡 느낀점

데이터 분석 강의를 들으며 새롭게 접하는 함수나 툴이 많아 학습에 어려움을 겪었다. 강사님께 자문을 구해보니 함수를 외우는 것이 아닌 그때그때 꺼내서 적용시킬 수 있는 경험과 생각의 폭을 늘리는 과정이 중요하다고 말씀하셨다. 다양한 데이터들 중 흥미있는 것을 골라 추출하고 떼어내고 붙이는 등의 기믹에 재미를 붙인다면 효율적으로 학습할 수 있을 것 같다.