데이터 분석의 시작: Pandas & Google Colab

Slide 1 / 60
  • 강의명: 정치 데이터 분석 실습 (Political Data Analysis Lab)
  • 주차: 제2주차 (Week 2)
  • 주제: 데이터 정리 및 기술 통계 (Data Wrangling & Descriptive Statistics using Pandas)
  • 도구: Google Colab, Python 3.x, Pandas Library
  • 강사: [김찬우]
Socratic Question
'데이터 분석의 시작: Pandas & Google Colab'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

오늘 우리가 달성할 목표 (Learning Objectives)

Slide 2 / 60
  • 클라우드 분석 환경 숙달: Google Colab의 인터페이스를 익히고, 클라우드 환경에서 파이썬 분석 환경을 독립적으로 설정 및 최적화한다.
  • Pandas 자료구조의 심층 이해: 데이터 분석의 뼈대인 Series와 DataFrame의 차이점을 명확히 구분하고, 정치 데이터를 객체화하는 논리를 습득한다.
  • 데이터 로딩의 정석과 인코딩 해결: 외부 데이터(CSV, Excel)를 불러올 때 발생하는 인코딩 오류를 진단하고, 다양한 옵션을 통해 데이터를 정확하게 로드한다.
  • 데이터의 첫인상 파악 (EDA 기초): 수만 행의 방대한 데이터셋을 마주했을 때, 구조와 품질을 1분 내로 진단할 수 있는 필수 메서드(Method) 활용법을 익힌다.
Socratic Question
'오늘 우리가 달성할 목표 (Learning Objectives)'의 과정을 데이터 분석에 적용할 때, 분석가의 주관이 개입될 수 있는 여지는 어떤 부분일까요?

Part 1. Google Colab 환경 구축 및 분석 전략

Slide 3 / 60

왜 정치 데이터 분석에 Google Colab인가?

  • 제로 설정(Zero Configuration): 로컬 PC의 OS(Windows, Mac) 환경에 상관없이 브라우저만 있으면 즉시 동일한 분석 환경을 보장합니다. Anaconda 설치 시 발생하는 경로 오류나

라이브러리 충돌 문제를 원천 차단합니다.

  • 강력한 하드웨어 가용성: 선거 결과와 같은 대규모 로우 데이터를 처리할 때 유리한 고성능 서버 자원(RAM, GPU/TPU)을 무료로 할당받아 사용합니다.
  • 협업 및 기록의 최적화: 분석 코드를 구글 문서처럼 실시간 공유하여 팀 프로젝트를 수행할 수 있으며, 마크다운(Markdown) 기능을 통해 분석의 근거와 정치적 함의를 코드 사이에 상세히 서술할 수 있습니다.
  • 모바일 접근성: 태블릿이나 다른 기기에서도 언제 어디서든 분석 코드를 확인하고 수정할 수 있는 영속성을 가집니다.
Socratic Question
이 슬라이드의 'Part 1. Google Colab 환경 구축 및 분석 전략' 내용을 바탕으로, 분석 대상이 되는 사회적 소수자나 예외적 사례들이 배제될 가능성에 대해 어떻게 생각하시나요?

Colab 필수 설정 (1): 시각화 한글 폰트 문제 해결

Slide 4 / 60
  • 문제 상황: 파이썬의 표준 시각화 도구인 Matplotlib은 영문 기반으로 설계되어, 한글 정당명이나 지역명을 출력하면 글자가 사각형('ㅁ')으로 깨지는 현상이 발생합니다.

해결 프로세스 (순서 엄수):

폰트 설치 코드 실행:


!sudo apt-get install -y fonts-nanum
!sudo fc-cache -fv
!rm ~/.cache/matplotlib -rf


      
  • 런타임 초기화: 상단 메뉴의 **[런타임] - [런타임 다시 시작]**을 반드시 클릭해야 설치된 폰트가 시스템에 등록됩니다.
  • 설정 적용: 이후 코드에서 plt.rc('font', family='NanumBarunGothic') 명령어로 폰트를 활성화합니다.
Socratic Question
사회 현상을 정량화하는 과정에서, 'Colab 필수 설정 (1): 시각화 한글 폰트 문제 해결'의 개념이 현실의 복잡성을 어떻게 단순화하거나 왜곡할 위험이 있나요?

Colab 필수 설정 (2): 라이브러리 임포트의 표준

Slide 5 / 60

데이터 분석의 '도구 상자'를 여는 과정입니다. 표준 약칭(Alias)을 사용하여 가독성을 높입니다.

표준 관례(Naming Convention):


import pandas as pd # 데이터 프레임 핸들링의 핵심 (Panels Data)
import numpy as np # 고성능 수치 계산 및 결측치(NaN) 처리
import matplotlib.pyplot as plt # 정적 그래프 시각화
import seaborn as sns # 통계 기반의 미려한 시각화 도구


      

왜 as pd인가? 코드 작성 효율을 높일 뿐만 아니라, 전 세계 데이터 과학자들이 공유하는 일종의 '언어'입니다. pd라는 접두사만 보고도 이 함수가 Pandas의 기능임을 즉각 인지할 수 있게 합니다.

Socratic Question
'Colab 필수 설정 (2): 라이브러리 임포트의 표준'의 과정을 데이터 분석에 적용할 때, 분석가의 주관이 개입될 수 있는 여지는 어떤 부분일까요?

데이터의 통로: Google Drive 마운트 (Mounting)

Slide 6 / 60

클라우드 가상 컴퓨터에 내 구글 드라이브 폴더를 '하드디스크'처럼 연결하는 과정입니다.

연결 절차:


from google.colab import drive
      

drive.mount('/content/drive')

  • 동작 원리: 실행 시 구글 계정 인증 창이 뜨며, 승인 후에는 드라이브 내의 CSV 파일을 로컬 경로처럼 사용할 수 있습니다.
  • 경로 팁: /content/drive/MyDrive/ 경로 아래에 강의용 폴더(예: Political_Analysis)를 만들어 관리하면 관리가 용이합니다. 왼쪽 파일 탐색기에서 마우스 우클릭으로 '경로 복사'

기능을 활용하면 오타를 줄일 수 있습니다.

Socratic Question
만약 '데이터의 통로: Google Drive 마운트 (Mounting)'에서 다룬 절차를 생략한다면, 최종 분석 결과에 어떤 치명적인 편향이 발생할 수 있을까요?

Part 2. Pandas의 핵심 철학: 자료구조의 이해

Slide 7 / 60

"Pandas는 데이터를 다루는 파이썬의 엑셀입니다."

  • Series (시리즈): 인덱스(Index)라는 주소를 가진 1차원 데이터 열입니다. 엑셀에서 특정 열(Column) 하나를 떼어낸 것과 같습니다. 모든 원소는 동일한 데이터 타입을 가져야 효율적입니다.
  • DataFrame (데이터프레임): 행(Row)과 열(Column)로 구성된 2차원 표입니다. 여러 개의 Series가 옆으로 붙어 만들어진 구조이며, 분석의 가장 기본 단위가 됩니다.
  • Index (인덱스): 데이터의 행 주소입니다. 단순 숫자(0, 1, 2...)일 수도 있고, 지역명이나 정당명 같은 문자열일 수도 있습니다. 데이터를 빠르게 검색(Lookup)하는 키 역할을 합니다.
Socratic Question
만약 'Part 2. Pandas의 핵심 철학: 자료구조의 이해'에서 다룬 절차를 생략한다면, 최종 분석 결과에 어떤 치명적인 편향이 발생할 수 있을까요?

Series: 데이터의 원자 단위

Slide 8 / 60

단순한 리스트와 달리 '의미 있는 이름'을 가진 인덱스를 가집니다.

정치 데이터 생성 예시:


# 후보별 지지율을 시리즈로 표현
polls = pd.Series([42.5, 38.1, 12.4],
index=['후보A', '후보B', '후보C'],
name='지지율')
print(polls)


      
  • 활용: 특정 컬럼 하나만 선택(df['candidate'])하면 결과는 항상 Series 형태가 됩니다. 시리즈 연산(예: 전체 지지율 합으로 나누기)을 통해 비율을 구하는 등의 작업이 매우 간편합니다.
Socratic Question
'Series: 데이터의 원자 단위'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

DataFrame: 데이터 분석의 실질적 전장

Slide 9 / 60

현실 세계의 복잡한 정치적 사건들은 여러 변수의 조합으로 설명됩니다. DataFrame은 이를 담기에 최적의 그릇입니다.

구성 요소 및 특징:

  • 행(Index): 각 관측치(개별 유권자, 개별 투표소, 개별 선거구 등).
  • 열(Columns): 변수(정당, 득표수, 연령대, 소득 수준 등).
  • 유연성: 각 열은 서로 다른 데이터 타입(문자, 숫자, 날짜)을 가질 수 있습니다.

정형 데이터 분석의 흐름은 "외부 데이터를 읽어와 DataFrame으로 만들고, 이를 가공하여 결론을 내는 과정"으로 정의됩니다.

Socratic Question
'DataFrame: 데이터 분석의 실질적 전장'의 과정을 데이터 분석에 적용할 때, 분석가의 주관이 개입될 수 있는 여지는 어떤 부분일까요?

실습 데이터 시나리오: 제21대 총선 분석

Slide 10 / 60

우리는 가상의 혹은 실제 공공데이터인 **"제21대 국회의원 선거 결과 요약.csv"**를 분석합니다.

주요 변수(Variable) 설명:

  • sgg_name: 선거구 명칭 (예: 서울 종로구)
  • party: 소속 정당 (예: 더불어민주당, 미래통합당 등)
  • candidate: 후보자의 성명
  • votes: 해당 후보자가 얻은 유효 득표수
  • voter_turnout: 해당 선거구의 전체 투표율 (%)

이 데이터를 통해 지역별 정당 지지 강도와 투표율 사이의 상관관계를 탐색할 예정입니다.

Socratic Question
'실습 데이터 시나리오: 제21대 총선 분석'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

데이터 로딩의 모든 것: pd.read_csv()

Slide 11 / 60

텍스트 형태의 CSV 데이터를 메모리 상의 DataFrame 객체로 전환합니다.

실전 코드와 파라미터:

file_path = '/content/drive/MyDrive/data/election_21st.csv'


df = pd.read_csv(file_path, encoding='cp949', sep=',')


      

인코딩(Encoding) 트러블슈팅:

  • UnicodeDecodeError 발생 시: 윈도우 환경에서 작성된 한글 파일은 encoding='cp949' 또는 'euc-kr'를 사용해야 합니다.
  • 글로벌 표준: 맥(Mac)이나 리눅스 환경에서 생성된 파일은 보통 'utf-8'입니다.
  • 구분자(Separator): 콤마가 아닌 탭(\t)이나 세미콜론(;)으로 구분된 경우 sep 인자로 지정 가능합니다.
Socratic Question
사회 현상을 정량화하는 과정에서, '데이터 로딩의 모든 것: pd.read_csv()'의 개념이 현실의 복잡성을 어떻게 단순화하거나 왜곡할 위험이 있나요?

데이터 탐색 (1): .head() & .tail() 로 구조 훑기

Slide 12 / 60

수만 건의 선거 데이터를 한꺼번에 출력하면 가독성이 떨어지고 시스템 부하가 생깁니다.

주요 기능:


df.head(n): 상위 n개의 행을 보여줍니다. 데이터의 헤더(컬럼명)가 제대로 들어왔는지, 데이터가 밀리지 않았는지 확인합니다.

df.tail(n): 하위 n개의 행을 보여줍니다. 데이터의 끝부분에 합계나 불필요한 주석(Footnote)이 포함되어 데이터 오염을 일으키지 않는지 체크합니다.

      
  • 분석가의 습관: 데이터를 불러온 직후 가장 먼저 실행하여 데이터의 '모양새'를 확인하는 단계입니다.
Socratic Question
사회 현상을 정량화하는 과정에서, '데이터 탐색 (1): .head() & .tail() 로 구조 훑기'의 개념이 현실의 복잡성을 어떻게 단순화하거나 왜곡할 위험이 있나요?

데이터 탐색 (2): .shape & .columns 로 규모 파악

Slide 13 / 60

데이터의 외형적 스펙을 수치로 확인하는 단계입니다.

  • 규모 확인: df.shape
  • 출력 결과: (2540, 7) -> "2,540개의 행(사례)과 7개의 열(변수)로 구성되어 있음"을 의미합니다.
  • 변수 목록 확인: df.columns

출력 결과: Index(['sgg_name', 'party', ...], dtype='object')

      
  • 주의: 컬럼명에 앞뒤 공백이 있거나(' party '), 특수문자가 섞여 있으면 이후 분석에서 에러가 발생하므로 여기서 면밀히 확인해야 합니다.
Socratic Question
사회 현상을 정량화하는 과정에서, '데이터 탐색 (2): .shape & .columns 로 규모 파악'의 개념이 현실의 복잡성을 어떻게 단순화하거나 왜곡할 위험이 있나요?

데이터 탐색 (3): .info() 로 데이터 건강 진단

Slide 14 / 60

각 변수의 성격과 데이터의 결함 여부를 파악하는 가장 강력한 요약 도구입니다.

체크리스트:

  • Dtype(데이터 타입): 득표수(votes)가 숫자(int64)가 아닌 문자열(object)로 되어있다면, 나중에 덧셈이나 평균 계산이 불가능합니다. (전처리가 필요함을 암시)
  • Non-Null Count: 전체 행 개수보다 작은 숫자가 있다면 해당 열에 빈칸(결측치)이 있다는 뜻입니다. 여론조사 무응답 등을 어떻게 처리할지 전략을 세워야 합니다.
  • Memory Usage: 대용량 데이터 분석 시 내 시스템(Colab RAM)이 감당할 수 있는 수준인지 가늠합니다.
Socratic Question
만약 '데이터 탐색 (3): .info() 로 데이터 건강 진단'에서 다룬 절차를 생략한다면, 최종 분석 결과에 어떤 치명적인 편향이 발생할 수 있을까요?

데이터 탐색 (4): .describe() 로 통계적 특징 요약

Slide 15 / 60

기술 통계(Descriptive Statistics)의 집약체입니다. 데이터의 중심과 퍼짐 정도를 요약합니다.

주요 지표의 정치적 해석:

  • mean(평균): 후보자들의 평균적인 득표 수준.
  • 50%(중앙값): 극단적인 득표를 한 후보를 제외한 중간 수준의 지지세. 평균보다 중앙값이 낮다면 소수의 후보가 표를 독식하고 있음을 시사합니다.
  • std(표준편차): 득표수의 격차. 표준편차가 크다면 후보 간 지지율 양극화가 심하다는 증거입니다.

확장: df.describe(include='all')을 쓰면 문자열 데이터의 고유값 개수(unique), 최빈값(top) 등 범주형 데이터의 특성도 한꺼번에 파악할 수 있습니다.
      
Socratic Question
'데이터 탐색 (4): .describe() 로 통계적 특징 요약'의 과정을 데이터 분석에 적용할 때, 분석가의 주관이 개입될 수 있는 여지는 어떤 부분일까요?

Part 3. 데이터의 정밀 타격: Indexing & Slicing

Slide 16 / 60

"원하는 데이터만 정확하게 골라내는 것이 분석의 절반입니다."

정치 데이터는 보통 수천 개의 행(Row)으로 구성됩니다. 모든 데이터를 한꺼번에 분석하는 것은 노이즈가 많아 비효율적입니다. 따라서 특정 정당, 특정 지역, 혹은 특정 득표 구간의 데이터만 정밀하게 추출하는 과정이

분석의 성패를 결정합니다.

주요 도구 및 전략:

  • 열 선택 (Column Selection): 분석에 필요한 변수(예: 지지율, 연령대)만 골라내어 인지적 부하를 줄입니다.
  • loc (Label-based): 행과 열의 '이름'을 기준으로 접근합니다. 직관적이며 가독성이 높습니다.
  • iloc (Integer-based): 데이터의 '물리적 순서'를 기준으로 접근합니다. 자동화된 루프나 익명 데이터를 다룰 때 유용합니다.
  • Boolean Indexing: 논리 조건(참/거짓)을 활용해 특정 기준을 충족하는 '의미 있는 사례'만 필터링합니다.
Socratic Question
'Part 3. 데이터의 정밀 타격: Indexing & Slicing'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

특정 열(Column) 선택하기: 변수의 재구성

Slide 17 / 60

로우 데이터(Raw Data)에는 분석에 필요 없는 부가 정보가 많습니다. 필요한 변수만 떼어내어 새로운 분석 단위를 만듭니다.

단일 열 선택 (Series 반환):


# 한 개의 열만 가져오면 인덱스와 값만 남은 Series 형태가 됩니다.
party_list = df['party']


      

여러 열 선택 (DataFrame 반환):


# 여러 열을 선택할 때는 대괄호 안에 '리스트'를 넣어야 하므로 대괄호가 두 번([[ ]]) 쓰입니다.
subset = df[['sgg_name', 'candidate', 'votes']]


      
  • 정치적 맥락 및 임팩트: 수백 개의 설문 문항이 담긴 여론조사 데이터에서 '지지 정당'과 '세대' 변수만 추출하여 교차 분석(Cross-tabulation)을 준비할 때 필수적입니다. 데이터의 크기를 줄임으로써 연산

속도와 분석의 선명도를 동시에 잡을 수 있습니다.

Socratic Question
만약 '특정 열(Column) 선택하기: 변수의 재구성'에서 다룬 절차를 생략한다면, 최종 분석 결과에 어떤 치명적인 편향이 발생할 수 있을까요?

행(Row) 선택의 기초: 슬라이싱(Slicing)

Slide 18 / 60

파이썬의 기본 리스트 슬라이싱과 유사하게 행의 범위를 지정하여 데이터를 잘라냅니다.

코드 실습:


# 0번부터 9번 행까지 총 10개의 사례를 출력합니다.
top_10 = df[0:10]

# 마지막 5개 행만 확인하여 데이터 끝부분의 무결성을 검사합니다.
bottom_5 = df[-5:]


      
  • 주의사항 및 권장사항: df[0:10] 처럼 대괄호를 직접 쓰는 방식은 편리하지만, 행을 선택하는 것인지 열을 선택하는 것인지 혼동을 줄 수 있습니다. 코드의 명확성과 유지보수를 위해 가급적 명시적인 메서드인

.loc나 .iloc를 사용하는 습관을 들이는 것이 좋습니다.

Socratic Question
'행(Row) 선택의 기초: 슬라이싱(Slicing)'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

명칭 기반 선택: .loc[ ]의 정석

Slide 19 / 60
  • 정의: 인덱스의 '레이블(이름)'과 컬럼의 '이름'을 직접 지정하여 좌표를 찍듯 데이터를 가져옵니다.
  • 문법 체계: df.loc[행_이름, 열_이름]

실습 예시 (특정 선거구 데이터 추적):


# 인덱스가 '선거구명'으로 설정되어 있는 경우, 해당 선거구의 모든 변수를 가져옵니다.
jongno_data = df.loc['서울 종로구', :]


      

슬라이싱 응용 및 유의점:


# '서울'부터 '부산'까지의 모든 데이터, '정당'부터 '득표수' 컬럼까지 추출
regional_votes = df.loc['서울':'부산', 'party':'votes']


      
  • 핵심 차이: 일반적인 파이썬 슬라이싱과 달리 .loc의 슬라이싱은 '끝 지점(부산)'을 포함하여 결과를 반환합니다. 이는 사용자가 직관적으로 범위를 인지하게 하기 위함입니다.
Socratic Question
만약 '명칭 기반 선택: .loc[ ]의 정석'에서 다룬 절차를 생략한다면, 최종 분석 결과에 어떤 치명적인 편향이 발생할 수 있을까요?

위치 기반 선택: .iloc[ ]의 활용

Slide 20 / 60
  • 정의: 데이터의 실제 '순서(번호)'를 기반으로 접근합니다. (컴퓨터 공학적 인덱스인 0부터 시작)
  • 문법 체계: df.iloc[행_번호, 열_번호]

심화 사례:


# 가장 첫 번째 행(0)의 세 번째 열(2) 데이터를 즉시 확인합니다.
first_val = df.iloc[0, 2]

# 전체 데이터 중 뒤에서 10번째부터 끝까지, 처음 2개의 변수만 선택
recent_subset = df.iloc[-10:, :2]


      
  • 사용 전략: 데이터의 컬럼명이 한글이나 특수문자로 되어 있어 오타가 발생하기 쉽거나 너무 길 때, 혹은 프로그래밍적으로 for 문을 돌리며 n번째 데이터를 순차적으로 처리해야 할 때 매우 강력한 효율성을 발휘합니다.
Socratic Question
사회 현상을 정량화하는 과정에서, '위치 기반 선택: .iloc[ ]의 활용'의 개념이 현실의 복잡성을 어떻게 단순화하거나 왜곡할 위험이 있나요?

Boolean Indexing: 논리 기반의 데이터 필터링

Slide 21 / 60
  • 원리: 데이터프레임의 각 행에 대해 특정 조건의 참(True)/거짓(False)을 판별한 후, 오직 True인 행들만 골라 새로운 데이터셋을 구성합니다.

논리적 단계:


마스크 생성: mask = df['votes'] > 50000 (각 행이 조건에 맞는지 검사하여 True/False 시리즈 생성)

필터 적용: filtered_df = df[mask] (True인 행만 추출)

      

정치적 인사이트 도출 예시:

  • 당선 가시권 분석: "득표수 5만 표 이상의 유력 후보군만 따로 추출하여 그들의 공통점을 분석한다."
  • 투표 소외 지역 탐색: "투표율이 전국 평균인 60% 미만인 하위 지역구만 필터링하여 정책 지원의 우선순위를 결정한다."
Socratic Question
사회 현상을 정량화하는 과정에서, 'Boolean Indexing: 논리 기반의 데이터 필터링'의 개념이 현실의 복잡성을 어떻게 단순화하거나 왜곡할 위험이 있나요?

복합 조건 필터링 (다중 조건 결합)

Slide 22 / 60

정치적 상황은 단일 변수로 설명되지 않습니다. 여러 조건을 조합하여 정교한 분석 대상을 설정합니다.

  • AND 연산 (&): 모든 조건을 충족

# 'A정당' 소속이면서 동시에 '득표율 15%'를 넘겨 선거 보전금을 받는 후보들
cond1 = df['party'] == 'A정당'
cond2 = df['vote_rate'] >= 15
result_and = df[cond1 & cond2]


      
  • OR 연산 (|): 하나라도 충족

# 수도권 정치 지형 분석을 위해 '서울' 또는 '경기' 지역 데이터만 통합
result_or = df[(df['city'] == '서울') | (df['city'] == '경기')]


      
  • 실수 방지 팁: 각 조건은 반드시 **소괄호 ()**로 감싸야 합니다. 파이썬의 연산자 우선순위 때문에 괄호가 없으면 논리 연산보다 비교 연산이 늦게 실행되어 에러가 발생합니다.
Socratic Question
'복합 조건 필터링 (다중 조건 결합)'의 과정을 데이터 분석에 적용할 때, 분석가의 주관이 개입될 수 있는 여지는 어떤 부분일까요?

집합 기반 필터링: .isin( )의 효율성

Slide 23 / 60

여러 개의 OR 조건을 반복해서 쓰는 번거로움과 코드의 난잡함을 획기적으로 줄여줍니다.

  • 상황 설정: 원내 주요 3당(더불어민주당, 국민의힘, 정의당)의 데이터만 모아서 원외 정당들과 비교 분석하고 싶을 때.

코드 개선:


# 비효율적 방식: (df['party'] == 'A') | (df['party'] == 'B') | ...
# 효율적 방식: .isin() 활용
      

major_parties = ['더불어민주당', '국민의힘', '정의당']


df_major = df[df['party'].isin(major_parties)]


      
  • 장점: 코드가 한눈에 들어올 만큼 간결해지며, 분석 대상 정당 리스트를 외부 파일이나 변수로 따로 관리할 수 있어 확정성이 높습니다.
Socratic Question
이 슬라이드의 '집합 기반 필터링: .isin( )의 효율성' 내용을 바탕으로, 분석 대상이 되는 사회적 소수자나 예외적 사례들이 배제될 가능성에 대해 어떻게 생각하시나요?

텍스트 검색 필터링: .str.contains( )

Slide 24 / 60

수치 데이터가 아닌 텍스트 데이터 내에서 특정 패턴이나 키워드를 찾아냅니다.

정치 데이터 실무 활용:

  • 지역구 그룹핑: 선거구명에 '강남'이 들어가는 모든 구(갑, 을, 병)를 하나의 권역으로 묶어 분석할 때.
  • 프레임 분석: 후보자의 공약이나 연설문 텍스트 중 '복지', '안보', '공정' 등의 특정 가치 키워드가 포함된 사례를 분류할 때.

코드 실습:


# 선거구 이름에 '강남'이라는 텍스트가 포함된 모든 행을 추출합니다.
gangnam_districts = df[df['sgg_name'].str.contains('강남')]


      
  • 고급 팁: na=False 인자를 추가하면 결측치가 있는 행에서 에러가 나는 것을 방지할 수 있습니다.
Socratic Question
'텍스트 검색 필터링: .str.contains( )'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

데이터의 공백 처리: 결측치(NaN) 필터링

Slide 25 / 60

수집 과정에서 누락된 데이터는 분석 결과에 심각한 왜곡을 줄 수 있습니다. 이를 찾아내거나 제외하는 작업입니다.

도구 설명:

  • .isnull(): 데이터가 비어있으면(NaN) True를 반환. (문제 지점 발견)
  • .notnull(): 데이터가 채워져 있으면 True를 반환. (정상 데이터 추출)

정치적 의미 및 적용:

여론조사 로우 데이터에서 '지지 후보 없음' 혹은 '모름/무응답'으로 처리된 결측치를 제외하고, 실제 투표 의사가 있는 유효 응답자(Valid Respondents)만을 분석 모수로 확정할 때 사용합니다.


# 득표수 정보가 정상적으로 기입된 행만 남기고 분석을 진행합니다.
df_clean = df[df['votes'].notnull()]
      
Socratic Question
이 슬라이드의 '데이터의 공백 처리: 결측치(NaN) 필터링' 내용을 바탕으로, 분석 대상이 되는 사회적 소수자나 예외적 사례들이 배제될 가능성에 대해 어떻게 생각하시나요?

인덱스 재정렬: .reset_index()의 중요성

Slide 26 / 60

데이터를 필터링하거나 정렬하면 기존의 행 번호(0, 1, 5, 12...)가 그대로 유지됩니다. 이는 데이터의 이빨이 빠진 것과 같은 상태입니다.

발생할 수 있는 문제:

이후 분석에서 행 번호를 기준으로 반복문을 돌릴 때 에러가 발생합니다.

시각화 도구에서 데이터 포인트가 엉뚱한 위치에 찍힐 수 있습니다.

해결 방법:


# 필터링 직후 인덱스를 0부터 다시 순차적으로 부여합니다.
# drop=True를 생략하면 기존의 지저분한 인덱스가 새로운 컬럼으로 남아 데이터셋이 지저분해집니다.
df_filtered = df[df['votes'] > 10000].reset_index(drop=True)
      
Socratic Question
'인덱스 재정렬: .reset_index()의 중요성'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

데이터 정렬과 순위 매기기: .sort_values()

Slide 27 / 60

분석 결과를 시각화하거나 리포트를 작성할 때, 데이터를 논리적인 순서로 나열하여 설득력을 높입니다.

단일 기준 정렬:


# 득표수(votes)를 기준으로 가장 많은 후보부터 적은 후보 순(내림차순)으로 나열
df_sorted = df.sort_values(by='votes', ascending=False)


      

다중 기준 정렬 (계층적 정렬):

정치 분석에서는 "지역별로 먼저 묶고(가나다순), 그 안에서 득표율 순(내림차순)으로 보고 싶다"는 요구가 많습니다.


# city는 오름차순(True), votes는 내림차순(False)으로 각각 다른 기준 적용
df_multi_sorted = df.sort_values(by=['city', 'votes'],
ascending=[True, False])
      
Socratic Question
'데이터 정렬과 순위 매기기: .sort_values()'의 과정을 데이터 분석에 적용할 때, 분석가의 주관이 개입될 수 있는 여지는 어떤 부분일까요?

분포와 빈도 파악: .value_counts()

Slide 28 / 60

범주형(Category) 데이터의 빈도수를 계산하여 데이터의 전반적인 구성을 파악합니다.

분석 질문:

"이번 총선에서 가장 많은 후보자를 낸 정당은 어디인가?"

"선거구별로 출마한 후보자의 수는 보통 몇 명인가?"

실전 코드:


# 정당별 후보자 수를 카운트합니다.
party_counts = df['party'].value_counts()

# 숫자가 아닌 비율(%)로 보고 싶을 때
party_ratio = df['party'].value_counts(normalize=True) * 100


      
  • 의미: 이 결과를 통해 소수 정당의 원내 진입 가능성이나 특정 정당의 공천 규모를 즉각적으로 확인할 수 있습니다.
Socratic Question
만약 '분포와 빈도 파악: .value_counts()'에서 다룬 절차를 생략한다면, 최종 분석 결과에 어떤 치명적인 편향이 발생할 수 있을까요?

데이터 유니크성 확인: .unique( ) & .nunique( )

Slide 29 / 60

중복을 제거한 실제 데이터의 종류와 그 개수를 확인합니다.

분석 시나리오:

  • 종류 확인: df['party'].unique() -> "이번 선거에 등록된 모든 정당의 이름을 리스트로 확인하여 오타가 있는지 검사한다."
  • 개수 확인: df['sgg_name'].nunique() -> "전국 254개 선거구 중 데이터에 누락된 곳이 없는지 개수를 대조한다."
  • 데이터 클리닝 활용: 예를 들어 '국민의힘'과 '국민의 힘'이 별개로 존재한다면, unique()를 통해 이를 발견하고 하나로 합치는 전처리 작업을 수행해야 함을 알 수 있습니다.
Socratic Question
사회 현상을 정량화하는 과정에서, '데이터 유니크성 확인: .unique( ) & .nunique( )'의 개념이 현실의 복잡성을 어떻게 단순화하거나 왜곡할 위험이 있나요?

2부 종합 실습: "대한민국 정치 격전지(Battleground) 분석"

Slide 30 / 60
  • Mission: 여러분은 선거 전략가입니다. 다음 조건에 부합하는 '집중 관리 선거구' 리스트 battleground를 만드세요.

분석 조건:

  • 투표 열기: 전체 투표율(voter_turnout)이 전국 평균인 66.2%를 상회하는 지역.
  • 초박빙 승부: 당선자와 2위 후보 간의 득표 차이가 3,000표 이하인 선거구.
  • 가독성 확보: 인덱스를 0부터 재설정하고, 득표 차이가 가장 적은 '최대 격전지'부터 상단에 출력하세요.

작업 순서 가이드:


df['diff'] = ... 를 통해 1, 2위 간 득표 차이 파생 변수를 만듭니다. (다음 장에서 상세 학습)

      

& 연산자로 투표율 조건과 득표 차 조건을 결합합니다.

sort_values와 reset_index를 체이닝(Chaining)하여 결과를 완성합니다.

Socratic Question
'2부 종합 실습: "대한민국 정치 격전지(Battleground) 분석"'의 과정을 데이터 분석에 적용할 때, 분석가의 주관이 개입될 수 있는 여지는 어떤 부분일까요?

Part 4. 데이터의 재구성: 전처리와 변형

Slide 31 / 60

"쓰레기를 넣으면 쓰레기가 나온다 (Garbage In, Garbage Out)."

데이터 분석의 80%는 전처리에 소요됩니다. 수집된 정치 데이터는 절대 분석에 최적화된 상태가 아닙니다. 오타가 있을 수도 있고, 숫자가 문자로 인식되어 연산이 불가능할 수도 있으며, 날짜 형식이 파편화되어 시계열

분석을 방해하기도 합니다.

이번 섹션의 핵심 목표:

  • 데이터 결함의 진단과 처방: 누락된 값(NaN)이 통계적 왜곡을 일으키지 않도록 처리하고, 중복 수집된 사례를 정교하게 제거합니다.
  • 데이터 타입의 정밀 교정: 콤마(,)가 포함된 문자열 형태의 득표수를 계산 가능한 정수형(int)이나 실수형(float)으로 변환합니다.
  • 새로운 정치적 가치 창출: 기존 변수를 조합하여 '득표율', '1-2위 간 격차', '당선 확률'과 같은 고차원 파생 변수를 생성합니다.
  • 텍스트 표준화: 정당명이나 후보자 이름에 포함된 불필요한 공백과 오타를 일괄 수정하여 그룹화 분석의 정확도를 높입니다.
Socratic Question
'Part 4. 데이터의 재구성: 전처리와 변형'의 과정을 데이터 분석에 적용할 때, 분석가의 주관이 개입될 수 있는 여지는 어떤 부분일까요?

데이터의 건강검진: .info()와 .describe()의 심층 활용

Slide 32 / 60

전처리를 시작하기 전, 우리는 데이터의 '기저 질환'을 파악해야 합니다. 단순한 조회를 넘어 데이터의 무결성을 최종 점검하는 단계입니다.

정밀 진단 체크리스트:

  • Non-Null Count (결측치 비율): 전체 행 개수와 비교하여 특정 컬럼의 데이터가 너무 많이 비어있지는 않은지 확인합니다. (예: 비례대표 후보의 경우 지역구 정보가 비어있는 것이 정상인지 판단)
  • Dtype (데이터 타입의 적절성): 산술 연산이 필요한 득표수(votes)나 지지율이 object(문자열)로 되어 있지는 않은가? 이는 곧바로 산술 연산 에러로 이어집니다.
  • Memory Usage (자원 효율성): 데이터셋이 수백만 건일 경우, 메모리 점유율을 확인하여 데이터 타입을 경량화(예: float64를 float32로)할 필요가 있는지 결정합니다.

실전 분석 팁: df.describe(include='all')은 분석가의 가장 강력한 무기입니다. 숫자 데이터의 분포뿐만 아니라, 문자열 데이터에서 가장 자주 등장하는 정당(top)이 어디인지, 정당의
      

종류(unique)가 몇 개인지 등을 통해 데이터 수집의 편향성을 즉각 포착할 수 있습니다.

Socratic Question
'데이터의 건강검진: .info()와 .describe()의 심층 활용'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

데이터 타입의 마법: .astype( )을 이용한 강제 형변환

Slide 33 / 60

공공데이터 포털 등에서 다운로드한 CSV 파일은 숫자를 따옴표로 감싸거나 천 단위 구분 기호(,)를 포함하여 문자열로 인식되는 경우가 허다합니다.

타입 변환이 생존인 이유:


# 문자열 상태('100')에서는 더하기(+)를 수행하면 산술 합이 아닌 문자열 이어붙이기가 됩니다.
# 예: '100' + '200' 결과는 300이 아닌 '100200'이라는 엉뚱한 문자열이 됩니다.
# 따라서 반드시 분석 전에 타입 교정이 필요합니다.
df['votes'] = df['votes'].astype(int)


      
  • 고급 주의사항: 데이터에 결측치(NaN)가 하나라도 포함되어 있다면 파이썬의 기본 int 타입으로 바로 변환할 수 없습니다(NaN은 본질적으로 float이기 때문). 이 경우 결측치를 0 등으로 먼저 처리한 후

변환하거나, 결측치를 허용하는 float 타입으로 변환한 뒤 후속 조치를 취해야 합니다.

Socratic Question
이 슬라이드의 '데이터 타입의 마법: .astype( )을 이용한 강제 형변환' 내용을 바탕으로, 분석 대상이 되는 사회적 소수자나 예외적 사례들이 배제될 가능성에 대해 어떻게 생각하시나요?

수치형 데이터 정제: 특수문자 제거와 연쇄 변환

Slide 34 / 60

단순한 형변환(astype)이 실패하는 가장 큰 이유는 숫자 사이에 섞인 '불순물' 때문입니다. 콤마(,)나 '표', '명'과 같은 단위가 대표적입니다.

현장 기반 해결 시나리오 (득표수 정밀 정제):

  • 패턴 치환: str.replace를 사용하여 숫자 이외의 모든 기호를 공백으로 바꿉니다.
  • 연쇄 처리(Chaining): 치환 직후에 즉시 타입을 변환하여 코드의 간결성을 유지합니다.

# 정규표현식을 사용하거나 단순 replace를 활용하여 콤마를 제거합니다.
# 이후 바로 astype(int)를 호출하여 정수형 데이터프레임 열로 확정합니다.
df['votes'] = df['votes'].str.replace(',', '').astype(int)


      
  • 정치 분석의 시사점: 중앙선거관리위원회 등에서 복사하여 붙여넣은 데이터는 대부분 콤마를 포함하고 있습니다. 이 전처리 과정 없이 분석을 시도하면 모든 통계 함수가 에러를 뱉어내므로, 분석의 '입구'와 같은

과정입니다.

Socratic Question
만약 '수치형 데이터 정제: 특수문자 제거와 연쇄 변환'에서 다룬 절차를 생략한다면, 최종 분석 결과에 어떤 치명적인 편향이 발생할 수 있을까요?

결측치와의 전쟁: .fillna( )와 .dropna( )의 전략적 선택

Slide 35 / 60

비어있는 데이터(NaN)를 어떻게 다루느냐는 분석 결과의 신뢰도를 결정짓는 윤리적 문제이기도 합니다.

  • 전략 1: 과감한 제거 (.dropna)

특정 후보자가 사퇴하거나 등록 무효가 되어 데이터의 연속성이 깨진 경우, 해당 행을 분석 대상에서 제외하는 것이 통계적 오염을 막는 길입니다.


# '후보자명'이 비어있는 데이터는 유령 데이터로 간주하여 행 전체를 삭제합니다.
df_final = df.dropna(subset=['candidate'])


      
  • 전략 2: 합리적 채우기 (.fillna)

여론조사에서 '무응답'이 발생한 경우, 이를 단순히 삭제하기보다 0으로 처리하거나 전체 평균값(mean), 혹은 중앙값(median)으로 대체하여 모수를 유지합니다.


# 지지율 미응답 사례를 0%로 간주하여 계산의 일관성을 확보합니다.
df['support_rate'] = df['support_rate'].fillna(0)
      
Socratic Question
'결측치와의 전쟁: .fillna( )와 .dropna( )의 전략적 선택'의 과정을 데이터 분석에 적용할 때, 분석가의 주관이 개입될 수 있는 여지는 어떤 부분일까요?

중복 데이터 제거: .drop_duplicates( )로 유일성 확보

Slide 36 / 60

크롤링이나 여러 파일의 병합 과정에서 동일한 선거 결과가 중복 입력되는 경우가 빈번합니다.

실습과 응용:


# 선거구와 후보자 이름이라는 두 가지 기준이 모두 일치하는 중복을 찾아 제거합니다.
# keep='last' 옵션은 시간순으로 수집된 데이터 중 가장 최신의 정보를 남기겠다는 선언입니다.
df_unique = df.drop_duplicates(subset=['sgg_name', 'candidate'], keep='last')


      
  • 분석가의 통찰: 중복을 기계적으로 제거하기 전, '왜' 중복되었는지 파악해야 합니다. 단순 시스템 오류인지, 아니면 실제 '동명이인' 후보가 다른 정당으로 출마한 사례인지 확인하지 않으면 소중한 데이터를 손실할

위험이 있습니다.

Socratic Question
'중복 데이터 제거: .drop_duplicates( )로 유일성 확보'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

새로운 가치의 창조: 파생 변수(Derived Variable) 설계

Slide 37 / 60

원본 데이터에는 없지만, 분석가의 가설을 검증하기 위해 기존 변수들을 수학적으로 조합해 만든 새로운 지표입니다.

정치 데이터의 핵심 파생 변수:

  • 득표율(Vote Share): 단순히 표의 개수(votes)를 넘어, 해당 지역구 전체 투표수 대비 차지하는 비중을 계산하여 정치적 영향력을 수치화합니다.

df['vote_rate'] = (df['votes'] / df['total_votes']) * 100

      
  • 승패 격차(Margin): 1위와 2위 후보 간의 표 차이를 계산합니다. 이는 다음 선거의 '격전지'를 예측하는 가장 중요한 데이터가 됩니다.
  • 분석적 의의: 파생 변수는 시각화의 강력한 재료가 됩니다. 예를 들어 '득표율' 변수를 이용해 지도 위에 정당 지지 강도를 색깔로 입히는(Choropleth Map) 분석이 가능해집니다.
Socratic Question
'새로운 가치의 창조: 파생 변수(Derived Variable) 설계'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

복잡한 로직의 구현: np.where( )를 이용한 조건부 변수

Slide 38 / 60

단순 사칙연산을 넘어 "특정 조건에 따른 라벨링"을 수행합니다. 엑셀의 IF 함수와 동일한 역할을 수행합니다.

  • 사례 연구: 당선 안정권 및 경합권 분류

import numpy as np
# 득표율 50%를 기준으로 '과반 당선(Majority)'과 '기타(Others)'로 후보군을 이분화합니다.
# 이 과정은 향후 정당별 과반 의석 확보 가능성을 시뮬레이션할 때 기초가 됩니다.
df['result_type'] = np.where(df['vote_rate'] >= 50, 'Majority', 'Others')


      
  • 확장된 활용: 여당 후보는 1, 야당 후보는 0으로 코딩하는 등 회귀 분석을 위한 더미 변수(Dummy Variable) 생성 시에도 이 함수가 핵심적으로 사용됩니다.
Socratic Question
'복잡한 로직의 구현: np.where( )를 이용한 조건부 변수'의 과정을 데이터 분석에 적용할 때, 분석가의 주관이 개입될 수 있는 여지는 어떤 부분일까요?

텍스트 데이터의 표준화 (1): 노이즈 제거와 정규화

Slide 39 / 60

"더불어민주당", "민주당 ", "더민주" 등 제각각인 정당 명칭은 데이터 그룹화 시 서로 다른 그룹으로 인식되는 대참사를 일으킵니다.

  • 공백의 저주 해결: 텍스트 앞뒤에 보이지 않게 숨어있는 공백은 필터링 에러의 주범입니다.

# .str.strip() 메서드를 통해 모든 텍스트 열의 앞뒤 공백을 일괄 제거합니다.
df['party'] = df['party'].str.strip()


      

명칭 통합의 기술:


# 특정 단어를 포함(contains)하는 모든 행을 찾아 표준 명칭으로 강제 통일합니다.
# 이를 통해 파편화된 정당 명칭을 하나로 결속시킵니다.
df.loc[df['party'].str.contains('민주당'), 'party'] = '더불어민주당'
      
Socratic Question
이 슬라이드의 '텍스트 데이터의 표준화 (1): 노이즈 제거와 정규화' 내용을 바탕으로, 분석 대상이 되는 사회적 소수자나 예외적 사례들이 배제될 가능성에 대해 어떻게 생각하시나요?

텍스트 데이터의 표준화 (2): .map( )과 .replace( )

Slide 40 / 60

정해진 규칙(매핑 테이블)에 따라 데이터의 값을 대규모로 치환할 때 사용합니다.

딕셔너리 기반 매핑:


# 긴 행정구역 명칭을 분석 보고서용 약어로 일괄 변환합니다.
# {기존값 : 변경값} 형태의 딕셔너리를 작성하여 .map()에 전달합니다.
      
  • region_map = {'서울특별시': '서울', '경기도': '경기', '인천광역시': '인천'}

df['city_short'] = df['city'].map(region_map)


      
  • 기대 효과: 시각화 그래프의 축(Axis) 이름이 너무 길어 가독성이 떨어지는 문제를 원천적으로 방지하며, 데이터의 일관성을 부여하여 지역별 비교 분석을 용이하게 합니다.
Socratic Question
'텍스트 데이터의 표준화 (2): .map( )과 .replace( )'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

시간의 흐름 분석: pd.to_datetime( )

Slide 41 / 60

선거일, 후보 등록일, 여론조사 공표일 등은 단순 문자열이 아닌 '시간'으로 인식되어야 그 선후 관계와 간격을 분석할 수 있습니다.

날짜 객체로의 진화:


# 문자열 형태의 '2024-04-10'을 파이썬이 이해하는 날짜 객체(Datetime)로 바꿉니다.
df['election_date'] = pd.to_datetime(df['election_date'])

# 날짜 객체에서 '월'만 추출하거나 '요일'을 알아내는 연산이 가능해집니다.
df['month'] = df['election_date'].dt.month
df['weekday_name'] = df['election_date'].dt.day_name()


      
  • 정치적 인사이트: "D-Day 기준 지지율 변화 추이"나 "사전투표 기간(금, 토)과 본투표일(수) 간의 세대별 참여도 차이" 등을 분석하는 시계열 연구의 기초가 됩니다.
Socratic Question
'시간의 흐름 분석: pd.to_datetime( )'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

열 이름의 재정의: .rename( )

Slide 42 / 60

원본 데이터의 난해한 컬럼명을 분석 목적에 맞는 명확한 한글이나 영문으로 변경합니다.

방법론:


# columns 인자에 {기존컬럼명 : 신규컬럼명} 딕셔너리를 전달합니다.
# 분석 협업 시 팀원들이 데이터의 의미를 즉각 파악하도록 돕는 배려이기도 합니다.
df = df.rename(columns={'sgg_name': '선거구', 'votes': '득표수'})


      
  • 필수 주의사항: Pandas의 많은 메서드와 마찬가지로 rename은 원본을 직접 바꾸지 않고 복사본을 반환합니다. 따라서 inplace=True를 사용하거나, 위 예시처럼 변수에 결과값을 다시

할당(Re-assignment)해야 변경 사항이 영구히 저장됩니다.

Socratic Question
만약 '열 이름의 재정의: .rename( )'에서 다룬 절차를 생략한다면, 최종 분석 결과에 어떤 치명적인 편향이 발생할 수 있을까요?

데이터 프레임 수직 결합: pd.concat( )

Slide 43 / 60

시군구별로 흩어져 있는 수십 개의 엑셀 파일을 하나의 거대한 데이터셋으로 통합하는 과정입니다.

결합 시나리오:

seoul_df와 busan_df가 동일한 컬럼 구조(변수명)를 가지고 있을 때, 이를 위아래로 길게 이어 붙입니다.


# axis=0 옵션은 수직 결합(위아래)을 의미합니다.
# .reset_index(drop=True)를 호출하여 섞여버린 행 번호를 0부터 다시 정렬하는 것이 필수입니다.
total_df = pd.concat([seoul_df, busan_df], axis=0).reset_index(drop=True)
      
Socratic Question
사회 현상을 정량화하는 과정에서, '데이터 프레임 수직 결합: pd.concat( )'의 개념이 현실의 복잡성을 어떻게 단순화하거나 왜곡할 위험이 있나요?

전처리 파이프라인(Pipeline) 구축 전략

Slide 44 / 60

지금까지 개별적으로 학습한 전처리 도구들을 실제 분석에서는 하나의 유기적인 흐름으로 묶어 실행해야 합니다.

분석가가 지켜야 할 정석 순서:

  • 결함 진단: info()와 isnull()로 전체적인 누락 상태를 파악합니다.
  • 텍스트 정화: strip()과 replace()로 데이터의 형태적 통일성을 확보합니다.
  • 타입 확정: astype()과 to_datetime()으로 데이터의 성격을 분석 가능하게 바꿉니다.
  • 변수 확장: 산술 연산을 통해 분석의 핵심 지표(득표율 등)를 생성합니다.
  • 구조 최적화: 불필요한 열을 drop()하고, 이름을 rename()하여 최종 분석용 데이터셋을 확정합니다.
Socratic Question
'전처리 파이프라인(Pipeline) 구축 전략'의 과정을 데이터 분석에 적용할 때, 분석가의 주관이 개입될 수 있는 여지는 어떤 부분일까요?

실습: "선거 데이터 클리닝 챌린지 - 로우 데이터의 부활"

Slide 45 / 60
  • Mission: 가상의 오염된 데이터셋 dirty_election_data.csv를 완벽한 분석용 DataFrame으로 정제하세요.

상세 요구사항 (Step-by-Step):

  • 수치 정제: votes 컬럼에 포함된 콤마(,)와 특수문자를 제거하고 int64 타입으로 변환하세요.
  • 정당 통합: '국힘', '국민의힘 ', '국민의 힘' 등 유사한 명칭을 모두 '국민의힘'으로 단일화하세요.
  • 지표 생성: 전체 선거구 투표수 대비 개인 득표율을 계산하여 share 컬럼(%)을 만드세요.
  • 정책 변수 생성: 득표율에 따른 선거 비용 보전 구간을 라벨링하세요.
  • 15% 이상: '전액보전'
  • 10% 이상 15% 미만: '반액보전'
  • 10% 미만: '보전없음'
  • (힌트: 복잡한 조건은 np.select를 사용하면 가독성이 좋습니다.)
Socratic Question
'실습: "선거 데이터 클리닝 챌린지 - 로우 데이터의 부활"'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

Part 5. 데이터의 요약과 통계적 통찰

Slide 46 / 60

"숫자 뒤에 숨겨진 정치적 흐름을 읽는 법"

전처리가 끝난 데이터는 이제 깨끗한 상태입니다. 하지만 수만 행의 로우 데이터를 단순히 눈으로 훑는 것만으로는 거시적인 정치적 흐름을 파악할 수 없습니다. 수치화된 요약은 복잡한 현상을 단순화하여 의사결정을 돕는

강력한 도구입니다.

이번 섹션의 상세 목표:

  • 데이터 그룹화 (Groupby): 데이터를 정당별, 지역별, 연령대별 등 의미 있는 단위로 묶어 집계하는 기술을 습득합니다.
  • 기술 통계 (Descriptive Stats): 평균, 중앙값, 표준편차 등을 통해 데이터의 '중심'이 어디인지, 그리고 얼마나 '퍼져' 있는지 이해합니다.
  • 피벗 테이블 (Pivot Table): 엑셀의 핵심 기능을 Pandas에서 구현하여, 다차원적인 요약 보고서를 생성하는 법을 배웁니다.
  • Colab 실무: 클라우드 환경에서 분석 결과를 파일로 내보내고(Export), 한글 폰트 설정 등 시각화 준비를 마칩니다.
Socratic Question
'Part 5. 데이터의 요약과 통계적 통찰'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

집계의 핵심: .groupby( )의 작동 원리

Slide 47 / 60

groupby는 단순히 데이터를 묶는 것이 아니라, **Split(분할) - Apply(적용) - Combine(결합)**이라는 정교한 내부 논리를 거칩니다.

  • 정치 분석 사례: "각 정당별 평균 득표율은 얼마인가?"
  • # 1. Split: 전체 데이터를 정당(party)이라는 기준에 따라 여러 소집단으로 나눕니다.
  • # 2. Apply: 각 소집단의 득표율(vote_rate) 컬럼에 대해 평균(mean) 계산기를 돌립니다.
  • # 3. Combine: 계산된 정당별 평균값들을 하나의 표로 다시 합칩니다.

party_stats = df.groupby('party')['vote_rate'].mean()


      
  • 전문가의 Tip: 단일 통계량만으로는 부족할 때가 많습니다. 이럴 때는 .agg() 함수를 활용하여 리스트 형태로 여러 통계를 동시에 요청하세요.

# 정당별 득표율의 평균, 합계, 그리고 출마 후보자 수(count)를 한눈에 비교합니다.
multi_stats = df.groupby('party')['vote_rate'].agg(['mean', 'sum', 'count'])
      
Socratic Question
만약 '집계의 핵심: .groupby( )의 작동 원리'에서 다룬 절차를 생략한다면, 최종 분석 결과에 어떤 치명적인 편향이 발생할 수 있을까요?

다중 인덱스 그룹화: 지역별-정당별 교차 분석

Slide 48 / 60

"서울에서의 정당별 득표율과 경기에서의 득표율은 어떻게 다른가?"와 같은 복합적인 정치 지형을 분석할 때 사용합니다.

실전 코드:


# 시도(city)와 정당(party) 두 가지 변수를 리스트로 묶어 기준(index)으로 설정합니다.
# 그 결과로 각 지역 내에서의 정당별 총 득표수(votes)를 집계합니다.
city_party_grp = df.groupby(['city', 'party'])['votes'].sum()


      
  • 분석 포인트: 이 방식은 '지역 내 정당 점유율'을 정밀하게 분석하는 기초가 됩니다. 특정 지역에서 특정 정당이 압도적인지(Safe Seat), 아니면 여러 정당이 각축을 벌이는 경합 양상인지(Swing Seat)

수치로 입증할 수 있습니다. 결과물은 보통 계층적 구조(Multi-Index)를 가지게 됩니다.

Socratic Question
'다중 인덱스 그룹화: 지역별-정당별 교차 분석'의 과정을 데이터 분석에 적용할 때, 분석가의 주관이 개입될 수 있는 여지는 어떤 부분일까요?

데이터의 요약판: .pivot_table( ) 활용

Slide 49 / 60

groupby보다 시각적으로 더 직관적이고 보고서에 적합한 구조를 만들 때 사용합니다. 엑셀 사용자들이 가장 선호하는 Pandas 기능 중 하나입니다.

구조 설계의 4요소:

  • index: 행 방향(세로) 기준 (예: 시도별 구분)
  • columns: 열 방향(가로) 기준 (예: 정당별 구분)
  • values: 우리가 실제로 계산하고자 하는 숫자 (예: 득표수)
  • aggfunc: 어떤 계산을 할 것인가? (기본값은 평균이나, 선거 분석에서는 'sum' 혹은 'count'가 자주 쓰입니다.)

# 지역을 행으로, 정당을 열로 두어 득표수 합계를 한눈에 보여주는 표를 만듭니다.
pivot = df.pivot_table(index='city', columns='party', values='votes', aggfunc='sum')


      
  • 비즈니스적 활용: 이 구조는 추후 배우게 될 히트맵(Heatmap) 시각화의 입력 데이터로 가장 적합합니다. 색깔의 진하기를 통해 지역별 정당 지지 강도를 즉각적으로 보여줄 수 있습니다.
Socratic Question
'데이터의 요약판: .pivot_table( ) 활용'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

기술 통계 (1): 데이터의 중심 경향성(Central Tendency)

Slide 50 / 60

수만 명의 후보자나 수천 개의 선거구를 단 하나의 숫자로 대표할 수 있을까요? 상황에 맞는 '중심'을 찾는 것이 중요합니다.

주요 지표와 정치적 해석:

  • 평균 (Mean): 전체의 합을 개수로 나눕니다. 가장 대중적이지만, 한두 명의 '슈퍼 후보'가 얻은 수백만 표가 전체 평균을 끌어올려 대다수 평범한 후보의 현실을 왜곡할 수 있습니다.
  • 중앙값 (Median): 데이터를 일렬로 세웠을 때 딱 중간에 있는 값입니다. 극단적인 득표 차이가 존재할 때 평균보다 훨씬 현실적인 지표가 됩니다.
  • 최빈값 (Mode): 가장 흔하게 나타나는 값입니다. 예를 들어 "가장 많은 후보가 출마한 정당" 혹은 "가장 흔한 연령대"를 찾을 때 유용합니다.
  • 분석가의 경고: "우리 당 후보들의 평균 득표수"라는 수치에 현혹되지 마세요. 중앙값과의 차이가 크다면 소수의 스타 정치인에게 당의 지지세가 쏠려 있다는 신호일 수 있습니다.
Socratic Question
'기술 통계 (1): 데이터의 중심 경향성(Central Tendency)'의 과정을 데이터 분석에 적용할 때, 분석가의 주관이 개입될 수 있는 여지는 어떤 부분일까요?

기술 통계 (2): 데이터의 퍼짐(Dispersion)과 분포

Slide 51 / 60

"우리 당 지지율이 평균 30%다"라는 말보다 "지역별로 편차 없이 고르게 30%다"라는 정보가 선거 전략상 훨씬 중요할 수 있습니다.

산포 지표의 활용:

  • 표준편차 (Std): 각 데이터가 평균에서 얼마나 떨어져 있는지를 보여줍니다. 표준편차가 크다는 것은 후보 간 실력 차이가 극심하거나, 지역별 지지율 편차가 크다는 의미입니다.
  • 범위 (Max - Min): 가장 높은 득표율과 가장 낮은 득표율 사이의 거리를 파악합니다.
  • 사분위수 (Quartiles): 하위 25%(Q1), 50%(Q2, 중앙값), 75%(Q3) 지점을 확인합니다.
  • 심층 인사이트: 1위와 2위 후보 간의 득표 격차(Margin)에 대한 표준편차를 구해보세요. 이 수치가 낮을수록 전국적으로 박빙의 승부가 펼쳐졌음을 의미하며, 선거의 긴장감을 수치로 증명할 수 있습니다.
Socratic Question
이 슬라이드의 '기술 통계 (2): 데이터의 퍼짐(Dispersion)과 분포' 내용을 바탕으로, 분석 대상이 되는 사회적 소수자나 예외적 사례들이 배제될 가능성에 대해 어떻게 생각하시나요?

데이터 분포의 시각화 기초: 수치에서 그림으로

Slide 52 / 60

기술 통계 숫자를 보고 머릿속으로 그리던 분포를 실제로 확인하는 단계입니다.

도구와 해석:

  • 히스토그램 (.hist): 득표율 구간(예: 0~10%, 10~20%...)별로 후보자가 몇 명인지 막대로 보여줍니다. "대부분의 후보가 15% 보전선 근처에 몰려 있는가?"를 확인할 수 있습니다.
  • 박스 플롯 (.boxplot): 정당별 득표율 분포를 상자로 그려 비교합니다. 상자의 길이는 지지층의 견고함을, 상자 밖의 점들은 '이상치(특출나게 잘하거나 못한 후보)'를 나타냅니다.

# Pandas의 내장 기능을 활용해 빠른 시각화를 수행합니다.
# 구간(bins)을 20개로 쪼개어 세밀한 분포를 확인합니다.
df['vote_rate'].hist(bins=20, figsize=(10, 6))
      
Socratic Question
'데이터 분포의 시각화 기초: 수치에서 그림으로'의 과정을 데이터 분석에 적용할 때, 분석가의 주관이 개입될 수 있는 여지는 어떤 부분일까요?

상관관계 분석: .corr( )을 통한 관계의 발견

Slide 53 / 60

"두 변수가 함께 움직이는가?"라는 질문에 답합니다. 정치적 가설을 검증하는 첫걸음입니다.

상관계수 (Pearson's r)의 해석:

  • +0.7 이상: 강한 정비례 관계 (예: 지역 내 노년층 비율이 높을수록 특정 보수 정당 득표율이 높음)
  • -0.7 이하: 강한 반비례 관계 (예: 1인 가구 비율이 높을수록 특정 정당 득표율이 낮음)
  • 0 근처: 서로 아무런 관련이 없음 (예: 후보자의 이름 글자 수와 득표율)
  • 주의사항 (매우 중요): 상관관계가 높다고 해서 반드시 인과관계가 성립하는 것은 아닙니다. "투표날 비가 와서(A) 투표율이 낮아졌다(B)"는 상관관계일 수 있지만, 그 이면에 다른 정치적 역학 관계가 숨어있을 수

있음을 항상 의심해야 합니다.

Socratic Question
'상관관계 분석: .corr( )을 통한 관계의 발견'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

Google Colab 실무 (1): 구글 드라이브와의 완벽한 연동

Slide 54 / 60

Colab 세션이 종료되면 업로드한 파일은 사라집니다. 이를 방지하기 위해 구글 드라이브를 하드디스크처럼 연결합니다.

연동 프로세스:

왼쪽 사이드바의 '파일' 아이콘 클릭 후 '드라이브 마운트' 버튼을 누르거나, 아래 코드를 실행합니다.

팝업창에서 계정 권한을 허용합니다.

이제 MyDrive 폴더 내의 모든 파일을 경로만으로 불러올 수 있습니다.


from google.colab import drive
      

drive.mount('/content/drive')


# 실제 파일 경로 예시: 내 드라이브의 'data' 폴더 안의 파일
      

path = '/content/drive/MyDrive/data/election_results_2024.csv'


df = pd.read_csv(path)
      
Socratic Question
사회 현상을 정량화하는 과정에서, 'Google Colab 실무 (1): 구글 드라이브와의 완벽한 연동'의 개념이 현실의 복잡성을 어떻게 단순화하거나 왜곡할 위험이 있나요?

Google Colab 실무 (2): 한글 깨짐 현상 완벽 해결

Slide 55 / 60

Colab은 리눅스 기반 서버이므로 기본적으로 나눔 폰트 같은 한글 글꼴이 없습니다. 시각화 시 한글이 깨지는 현상은 분석가를 당황하게 만듭니다.

해결 시퀀스:

나눔 폰트를 서버에 설치합니다. (!apt-get install)

Matplotlib의 캐시를 새로고침하고 폰트를 지정합니다.

**반드시 '런타임 다시 시작'**을 해야 설정이 적용되는 경우가 많습니다.


# 폰트 설치 코드
!apt-get install -y fonts-nanum

import matplotlib.pyplot as plt
import matplotlib.font_manager as fm

# 설치된 나눔바른고딕 폰트 지정
      

plt.rc('font', family='NanumBarunGothic')

Socratic Question
'Google Colab 실무 (2): 한글 깨짐 현상 완벽 해결'의 과정을 데이터 분석에 적용할 때, 분석가의 주관이 개입될 수 있는 여지는 어떤 부분일까요?

분석 결과의 영구 저장: .to_csv( )와 .to_excel( )

Slide 56 / 60

힘들게 전처리하고 분석한 결과물은 파일로 내보내야 동료에게 전달하거나 보고서에 삽입할 수 있습니다.

실무 표준 코드:

  • # 1. CSV 저장: 용량이 작고 범용적입니다. 한글 깨짐 방지를 위해 utf-8-sig 권장.

df_summary.to_csv('result_summary.csv', index=False, encoding='utf-8-sig')

      
  • # 2. Excel 저장: 비전공자 동료들에게 전달할 때 가장 환영받습니다.

df_summary.to_excel('analysis_report.xlsx', sheet_name='2024_Results')


      
  • 전략적 팁: 원본 데이터는 그대로 두고, 전처리가 완료된 'Cleaned Data'를 별도의 파일로 저장해두세요. 그러면 나중에 분석 코드를 수정할 때 처음부터 다시 전처리를 반복하는 시간을 획기적으로 줄일 수

있습니다.

Socratic Question
'분석 결과의 영구 저장: .to_csv( )와 .to_excel( )'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

효율적인 Colab 관리를 위한 고급 팁

Slide 57 / 60
  • 런타임 자원 최적화: 대용량 데이터를 다룰 때는 런타임 > 런타임 유형 변경에서 고성능 CPU나 GPU를 선택할 수 있습니다. 하지만 일반적인 Pandas 분석은 기본 제공 자원으로도 충분합니다.
  • 코드 스니펫(Snippet)의 마법: 자주 사용하는 한글 폰트 설정 코드나 구글 드라이브 마운트 코드를 왼쪽 '코드 스니펫' 메뉴에 등록해두세요. 복사-붙여넣기 시간조차 아낄 수 있습니다.
  • 인터랙티브 테이블: Colab에서 google.colab.data_table 기능을 활성화하면, 일반적인 출력창이 엑셀처럼 필터링과 정렬이 가능한 인터랙티브 표로 변신합니다.

%load_ext google.colab.data_table

df # 이제 이 표는 동적으로 조작 가능합니다.

Socratic Question
사회 현상을 정량화하는 과정에서, '효율적인 Colab 관리를 위한 고급 팁'의 개념이 현실의 복잡성을 어떻게 단순화하거나 왜곡할 위험이 있나요?

실무 케이스 스터디: "실시간 선거 요약 대시보드 데이터 파이프라인"

Slide 58 / 60
  • 상황: 여러분은 뉴스룸의 데이터 팀장입니다. 투표 종료 직후 쏟아지는 데이터를 10분 안에 요약해서 그래픽 팀과 앵커에게 전달해야 합니다.

완성된 워크플로우:

  • 데이터 통합: 지역별로 들어오는 개별 CSV 파일들을 pd.concat으로 수직 병합합니다.
  • 정제: 정당명을 표준화하고, 득표수를 정수형으로 즉시 변환합니다.
  • 집계: pivot_table을 돌려 지역별 정당 득표 합계와 점유율을 계산합니다.
  • 필터링: 득표 차이가 2% 이내인 '초박빙 지역구'만 따로 뽑아 별도의 리스트를 만듭니다.
  • 공유: 결과를 구글 드라이브 공용 폴더에 엑셀 파일로 자동 저장하고 팀에 알립니다.
Socratic Question
'실무 케이스 스터디: "실시간 선거 요약 대시보드 데이터 파이프라인"'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?

2주차 과정 마무리 및 복습: 분석가의 자세

Slide 59 / 60

우리는 지난 2주 동안 파이썬의 기초 문법부터 Pandas를 활용한 정교한 데이터 조작, 그리고 통계적 요약까지 숨 가쁘게 달려왔습니다.

가슴에 새길 분석가 3계명:

  • 데이터의 민낯을 먼저 봐라: 화려한 분석보다 전처리 과정에서 데이터의 오류를 찾아내는 것이 분석의 품질을 결정합니다.
  • 질문이 도구를 결정한다: 무턱대고 groupby를 돌리기 전에, "내가 보고 싶은 것이 정당 간의 차이인가, 지역 간의 차이인가?"를 먼저 자문하세요.
  • 과정을 기록하라: 훗날의 나 혹은 동료가 여러분의 코드를 보고 똑같은 결과를 낼 수 있도록 마크다운과 주석을 꼼꼼히 남기세요.
Socratic Question
이 슬라이드의 '2주차 과정 마무리 및 복습: 분석가의 자세' 내용을 바탕으로, 분석 대상이 되는 사회적 소수자나 예외적 사례들이 배제될 가능성에 대해 어떻게 생각하시나요?

Q&A 및 다음 주 예고

Slide 60 / 60

오늘의 주요 토론 주제:

"결측치를 평균으로 채웠을 때 발생할 수 있는 정치적 편향은 무엇인가?"

"피벗 테이블의 구조를 바꿀 때(T) 가장 주의해야 할 점은?"

  • 3주차 예고: 데이터 시각화 (Matplotlib & Seaborn)

드디어 숫자를 그림으로 바꿉니다! 오늘 만든 통계 테이블을 바탕으로, 유권자의 마음을 한눈에 사로잡는 화려한 차트와 지도를 제작합니다.

  • 핵심 과제: 정당 지지율 추이 선 그래프 및 지역별 득표 지도(Cartogram) 기초 실습.
Socratic Question
'Q&A 및 다음 주 예고'의 기법을 활용하여 도출한 결론을 해석할 때, 우리가 가장 경계해야 할 논리적 비약은 무엇인가요?