데이터 분석 DAY1 - python, pandas, excel to dataframe

Jupyter Notebook

Cell

Command mode

  • 셀 자체에 영향, 셀을 추가, 삭제, 이동, ...
  • 셀 바깥쪽 클릭, ESC 누르기
  • a(bove) : 현재 셀 위에 셀 추가
  • b(elow) : 현재 셀 아래에 셀 추가
  • x : 현재 셀 자르기, 삭제 대응으로 사용 가능

Edit mode

  • 셀 안에다가 무언가 입력(에디트)
  • shift + enter : 현재 셀 실행
  • 셀 단위로 실행
  • 맨 마지막 줄 코드의 결과는 자동으로 출력해 줌.

Markdown : 문서 작업 가능(#으로 대, 소제목 구분)

  • 주피터 노트북에서 [View] - [Table of contents]를 통해 전체 항목을 확인 가능
  • vscode에서 노트 목록 확인 시 왼쪽 하단에 OUTLINE을 활성화하여 확인 가능

파이썬 기본 문법

  • 변수
  • 데이터에 이름을 만들어 주고 재사용 할 수 있음
# 새로운 데이터 생성
# => 변수에 할당
num = 3 + 4

# 원본 데이터를 바꿈
test = [1,2,3]
test.append(4)

Pandas

데이터

  • 행과 열이 있는 2차원 테이블
  • 자료구조(리스트, 딕셔너리)
  • 판다스 => 새로운 자료구조 2개를 제공(Series, DataFrame)

Series

  • 1차원 자료구조
  • 구성요소 2개 : index, values
  • 순서 있음 => for문, 슬라이싱
import pandas as pd

# A, B, C, D, E
math = [89,92,91,90,88]
eng = [90,91,90,92,89]

# 1차원 자료구조 => 시리즈 : 형변환
math_sr = pd.Series( math, index=['A', 'B', 'C', 'D', 'E'] )
eng_sr = pd.Series( eng, index=['A', 'B', 'C', 'D', 'E'] )

# 리스트 정렬
print( sorted( math ))

# 시리즈 변수 호출
math_sr

# 데이터 접근하기
# => 인덱스
# => 번호로도 여전히 가능

print(math_sr['A'])
print(math_sr[0])

# 슬라이싱 => 범위로 가져오기
# 숫자 범위 : 앞에는 포함, 뒤에는 포함 안됨
math_sr[ 0 : 3 ]

# 시리즈의 기능들
math_sr.sort_values( ascending=False )

# 필터링
# 조건에 따라 데이터를 가져오기
math_sr[ math_sr > 90 ]

# 시리즈의 연산
# value를 기준으로 같은 인덱스끼리 연산
# => 집합적인 연산
math_sr + eng_sr

# 시리즈의 연산2
# 시리즈와 값 하나 연산 => value를 기준으로 연산
math_sr + 100
print((math_sr + eng_sr) / 2)

 

DataFrame

  • 2차원 자료구조
  • 구성요소 3개 : column, index, values
  • 순서 => 기본적으로 행방향
# A, B, C, D, E
math = [89,92,91,90,88]
eng = [90,91,90,92,89]
kor = [92,90,89,90,91]

temp = {'math' : math, 'eng' : eng, 'kor' : kor}
grade_df = pd.DataFrame(temp, index=['A', 'B', 'C', 'D', 'E'])

# 데이터 접근하기
# 기본적으로 컬럼
grade_df['math']

# 인덱스를 기준으로 선택 => .loc
grade_df.loc['A']

# 한 포인트 접근
# .loc[ 인덱스, 칼럼 ]
grade_df.loc['A', 'math'] # A 학생의 수학 점수
grade_df.loc['B', 'eng']

# 슬라이싱 => 행으로 잘라줌
grade_df[:2] # 앞에서 2개
grade_df[-2:] # 뒤에서 2개

# 기능들
grade_df.sort_values(by=['math', 'eng'], ascending=False)

# 필터링
# 조건에 맞는 데이터를 가져오기
# df에서 조건을 쓸때 어떤 칼럼을 기준으로 조건을 주는 것인지 명확히
grade_df[ grade_df['math'] > 90 ]

# 조건 2개
# 논리연산 : and => &, or => |, not => ~
# 가로로 연산순서를 정확히
grade_df[ (grade_df['eng'] > 90) & (grade_df['math'] > 90) ]
grade_df[ (grade_df['eng'] > 90) | (grade_df['math'] > 90) ]

# df에서 시리즈의 연산
# df에서 어떤 칼럼을 가지고 와서 연산
# => df에 새로운 컬럼으로 추가
grade_df['total'] = grade_df['math'] + grade_df['eng'] + grade_df['kor']
grade_df['avg'] = grade_df['total'] / 3

 

DF 연습

import pandas as pd   # 새로운 자료구조 2개
import numpy as np    # 여러가지 집합적인 수학연산
import matpllotlib.pyplot as plt   # 데이터 시각화 기본
import seaborn as sns   # 시각화 도우미

titanic_df = sns.load_dataset('titanic')
titanic_df[ : 3 ]
titanic_df[ -3 : ]

# 몇 명이 죽었나
live = 0
dead = 0

for val in titanic_df['survived']:
	if val == 1:
    	live += 1
    else:
    	dead += 1
    
    print(live, dead)

titanic_df['survived'].value_counts( normalize=True )

# 성별에 따라 생존률에 영향을 줄까
titanic_df['sex'].unique()

titanic_df.loc[titanic_df['sex']=='male', 'sex'].value_counts()
titanic_df.loc[(titanic_df['sex']=='male') & (titanic_df['survived']==1), 'sex'].value_counts  # 남자 중 생존자 수

male = titanic_df[ titanic_df['sex'] == 'male' ]
male['survived'].value_counts( normalize=True )

female = titanic_df[ titanic_df['sex'] == 'female' ]
female['survived'].value_counts( normalize=True )

# 정렬 => 나이순으로 오름차순 정렬, 같은 나이는 성별로 정렬
titanic_df.sort_values(by=['age', 'sex'], ascending=True)

# 필터링 연습
# 죽었음
condition1 = titanic_df['survived']==0
# 남자
condition2 = titanic_df['sex'] == 'male'
# 3클래스
condition3 = titanic_df['pclass'] == 3
# 나이가 20이상
condition4 = titanic_df['age'] >= 20
# 25 미만
condition5 = titanic_df['age'] < 25

titanic_df[ condition1 & condition2 & condition3 & condition4 & condition5 ]

 

엑셀 데이터를 DF로 정리하는 연습

엑셀을 파이썬으로 읽어오기

  • 첫번째 행을 칼럼으로 세팅
  • header, index_col, usecols, skiprows, na_values
# 메타문자
# \ + 정해진 알파벳 => 특수한 효과를 가져옴
# r => raw, 뒤에 있는 문자열을 문자 그 자체로만 해석

print(r'python\npython')

# 엑셀을 파이썬으로 읽어오기
import pandas as pd
file = r'C:\Users\user\Desktop\실습 데이터\졸업생 진로 현황 데이터\졸업생의 진로 현황(전체).xlsx'
raw_df = pd.read_excel(file, sheet_name=0)

 

셀병합 있는 DF 정리

  • 컬럼 => 인덱스 => 데이터 값
# 컬럼 정리
# 1. 사용할 컬럼 정하기
# 2. 컬럼명을 사용하기 좋게 바꾸기

raw_df.columns
use_cols = ['지역', '정보공시 \n 학교코드', '학교명', '졸업자.2', '(특수목적고)과학고 진학자.2', '(특수목적고)외고,국제고 진학자.2']

# 여러개의 컬럼을 동시에 선택 => 컬럼명들을 리스트로 묶어주면 됨
raw_df2 = raw_df[ use_cols ]

# 2. 컬럼명을 사용하기 좋게 바꾸기
raw_df2.columns = ['reg', 'code', 'name', 'grads', 'sci', 'intl']

# 컬럼의 찌거기 삭제
raw_df3 = raw_df2.drop( 0 )

 

  • datetime
# 인덱스 정리
# 보통의 경우는 그냥 0,1,2,3, ... 그대로 씀
# 시계열 데이터는 인덱스를 시간 형식의 데이터로 세팅해줌

# 데이터 값 정리
# 1. 결측 데이터 체크
# 2. 데이터 타입 체크

# 1. 결측 데이터 체크
# NaN (<- 실수, 구조상 없음)

# 결측 데이터 집계
# isna => 앞에 모든 데이터에 NaN인지 조건문을 검

raw_df3.isna().sum()

# reg 컬럼이 NaN인 데이터를 찾아보자!
raw_df3[ raw_df['reg'].isna() ]

# 결측 데이터 일일이 바꾸기
raw_df3.loc[588, 'reg'] = '서울특별시 마포구'
raw_df3.loc[3011, 'reg'] = '부산광역시 해운대구'

raw_df3.loc[ 588 ]

# 새로운 데이터를 만들때 메모리 적으로 문제가 될 수는 있어도 새로 쓰는 것이기 때문에 덮어쓰기에 문제되지 않음
raw_df4 = raw_df3.dropna().copy()

# 2. 데이터 타입 체크
# 각 컬럼의 데이터 타입 => 통일되어 있음!
# 각 속성별로 적절한 데이터 타입으로 세팅되어 있나
# int => int32, int64
# float => float32, float64
#		=> datetime
# str   => object

raw_df4.dtypes

grad_df = raw_df4.reset_index(drop=True)

 

최종 코드

import pandas as pd

file = r'C:\Users\user\Desktop\실습 데이터\졸업생 진로 현황 데이터\졸업생의 진로 현황(전체).xlsx'

raw_df = pd.read_excel(file, sheet_name=0)

# 사용할 컬럼
use_cols = ['지역', '정보공시 \n 학교코드', '학교명', '졸업자.2', '(특수목적고)과학고 진학자.2', '(특수목적고)외고, 국제고 진학자.2']
raw_df2 = raw_df[ use_cols ]
# 영문으로
raw_df2.columns = ['reg', 'code', 'name', 'grads', 'sci', 'intl']
raw_df3 = raw_df2.drop( 0 )

# 결측값 정리
raw_df3.isna().sum()
raw_df3[ raw_df3['reg'].isna() ]
raw_df3.loc[588, 'reg'] = '서울특별시 마포구'
raw_df3.loc[3011, 'reg'] = '부산광역시 해운대구'

raw_df4 = raw_df3.dropna().copy()

# 데이터 타입 체크
raw_df4.dtypes

# 문자 => 숫자
raw_df4['grads'] = pd.to_numeric(raw_df4['grads'])
raw_df4['sci'] = pd.to_numeric(raw_df4['sci'])
raw_df4['intl'] = pd.to_numeric(raw_df4['intl'])

# 인덱스 초기화
grad_df = raw_df4.reset_index(drop=True)

 

DF의 주요 기능 5가지 + 1가지

  • 시리즈의 연산, 필터링, apply, groupby, pivot + merge
# 시리즈의 연산
# 테이블의 칼럼을 연산 => 새로운 칼럼
grad_df['spc_N'] = grad_df['sci'] + grad_df['intl']
grad_df['spc_R'] = (grad_df['spc_N'] / grad_df['grads'] * 100).round(2)

# 필터링
# 졸업생이 100명 이상인 학교 중 특목 진학률 높은 학교 20개
cond1 = grad_df['grads'] >= 100
grad_df[cond1].sort_values(by='spc_R', ascending=False)[:20]

# apply
# 한 열에 모든 데이터들에게 똑같은 코드를 일괄적으로 적용
def get_sido( x ):
	return x.split( '' )[0]

def get_sigungu( x ):
	return x.split( '' )[1]
    
grad_df['sido'] = grad_df['reg'].apply(get_sido)
grad_df['sigungu'] = grad_df['reg'].apply(get_sigungu)

# 서울특별시 내에서 진학률이 높은 20개
temp = grad_df['sido'] == '서울특별시'
grad_df[ temp ].sort_values(by='spc_R', ascending=False)[:20]
grad_df['reg'].unique()

# 집계
# 여러 데이터를 하나의 숫자나 문자로 표현
# mean, sum, max, min, count

grad_df['spc_R'].mean()
grad_df['grads'].mean()

# group by
# 특정 카테고리 별로 묶어서 집계
# 결과가 1차원

grad_df.groupby( 'sido' )['spc_R'].mean()
temp = grad_df.groupby( 'sido' )['grads'].sum()
temp.sort_values(ascending=False)

# 학교 개수
temp = grad_df.groupby( 'sido' )['name'].count()
temp.sort_values(ascending=False)

# group by를 이용해서 남녀 생존률 계산
# group by는 1차원
titanic_df.groupby( ['sex', 'pclass', 'embarked'] )['survived'].mean()

# pivot
# 2차원 집계
pd.pivot_table( titanic_df, index='sex', columns='pclass', values='survived', aggfunc='mean', margins=True)
# merge
# 옆으로 합치기
# 한번에 2개의 df를 합쳐줌
# how : 교집합, 합집합, 한쪽기준
grad_df['sido']

# 위도, 경도가 있는 2번째 엑셀 가져오기
path = r'C:\Users\user\Desktop\실습 데이터\졸업생 진로 현황 데이터\공시대상학교정보(전체).xlsx'
school_inform = pd.read_excel(path)

# 컬럼 파트
# 1. 사용할 컬럼 추리기
school_inform.columns

use_cols = ['정보공시 \n 학교코드', '위도', '경도', '학교명']

school_inform2 = school_inform[ use_cols ]

# 2. 컬럼명을 바꾸기
school_inform2.columns = ['code', 'lat', 'long', 'name']

# 데이터 값 파트
# 1. 결측 데이터 체크
school_inform2.isna().sum()

school_inform2[ school_inform2['lat'].isna() ]
school_inform2.dtypes

grad_df[:3]

school_inform2[:3]

total_df = pd.merge( grad_df, school_inform2, left_on='code', right_on='code', how='inner')

total_df.to_excel( r'학군연습.xlsx', index=False )