셀프스터디/빅데이터 분석기사

[11.24 수] 빅데이터 분석기사 실기 - Pandas (24~29강)

티로즈 2021. 11. 24. 22:30

1. 파일 읽어오기

  • csv 파일 : pd.read_csv('파일이름', encoding='cp949', low_memory=False)
    • encoding='cp949' : 한글이 포함되어 있는 경우 encoding 방식을 지정
    • low_memory=False : column에 여러 type의 데이터가 섞여 있으면 DtypeWarning이 발생하며 이때, dtype option으로 타입을 명시해주거나 low_memory=False를 사용한다.
# [4-1] 제과점에 대한 파일 './data_03/bread_data.csv'을 
# encoding='cp949' 를 사용하여 읽어와 df라는 이름을 붙인다
# low_memory=False 또는 dtype={'건물소유구분명': object, '전통업소지정번호': object}를 사용하여 Warning를 제거할 수 있음
df = pd.read_csv('./data_03/bread_data.csv', encoding='cp949', dtype={'건물소유구분명'object'전통업소지정번호'object})

 

2. 데이터 구조 확인

  • DataFrame.shape : 데이터 프레임의 행, 열의 수를 tuple로 반환
  • DataFrame.head(n=5) : 처음부터 n개 행의 데이터 가져오기
  • DataFrame.tail(n=5) : 마지막 n개 행의 데이터 가져오기
  • DataFrame.info(memory_usage='deep') : 데이터 프레임의 row 개수 및 각 column의 Non null, dtype 정보 및 메모리 사용량을 확인함
# [4-2] df의 행, 열의 개수를 확인한다
df.shape
# [4-3] df의 첫 1개 열을 출력해 확인한다
df.head(1)
# [4-4] df의 행, 열에 대한 개수, 각 열 별 데이터 개수 및 dtype, 
# 메모리 사용량을 확인합니다.
df.info(memory_usage='deep')

 

3. DataFrame의 Series

DataFrame의 한 개의 column은 Series이다.
  • DataFrame[컬럼명] : 컬럼 1개를 Series로 반환함
  • DataFrame[[컬럼명1, 컬럼명2, ...]] : 컬럼 목록에 있는 컬럼을 가져옴
    • 컬럼 목록에 1개의 컬럼만 있어도 DataFrame이 반환됨
Series.value_counts() : 데이터 별 개수를 Series로 반환
  • NA Value가 있다면 불포함
# [4-5] df의 '상세영업상태명'에 대해 값별 개수를 구합니다.
df['상세영업상태명'].value_counts()
df['폐업일자'].value_counts(normalize=True, dropna=False)
# [4-6] df의 '상세영업상태코드'에 대해 값별 개수를 구합니다.
df['상세영업상태코드'].value_counts()   # 1: 영업, 2: 폐업
# [4-7] df의 컬럼 중에 
# '인허가일자', '상세영업상태코드', '폐업일자', '소재지전체주소', '사업장명', '업태구분명'만 가져옵니다.
# 이름을 bread로 정하고, 처음부터 3개 행을 출력해 봅니다.
bread = df[['인허가일자''상세영업상태코드''폐업일자''소재지전체주소''사업장명''업태구분명']]
bread.head(3)

 

4. 파생정보 추가

Series의 str Accessor 사용
Series.unique() : 중복 데이터의 제거 후 배열로 반환, NA Value가 있다면 포함

# [4-8] bread 의 '소재지전체주소' 중 시/도에 대한 정보(목록)를 추출합니다.
bread['소재지전체주소'].str.split().str[0]

 

5. Boolean indexing 사용하여 조건에 맞는 데이터 가져오기

Boolean indexing 사용하여 조건에 맞는 데이터 가져오기
  • DataFrame.loc[조건, :]
  • DataFrame[조건]
  • 조건은 boolean dtype이어야 하며 행의 수와 같아야 함
  • 복잡한 조건 작성
    • (조건1) | (조건2) : 조건1 또는 조건2를 만족하는 데이터
    • (조건1) & (조건2) : 조건1, 조건2 모두 만족하는 데이터
    • ~(조건) : 조건이 거짓인 데이터
# [4-9] bread에서 소재지전체주소의 처음이 '서울특별시'이면서,
# '업태구분명'이 '제과점영업'인 것만 추출합니다.
condition1 = bread['소재지전체주소'].str.split().str[0] == '서울특별시'
condition2 = bread['업태구분명']=='제과점영업'
bread = bread[condition1 & condition2]
bread.head(2)
# [4-10] df, bread의 행/열 정보를 확인합니다.
df.shape, bread.shape

 

6. 새로운 컬럼 추가

DataFrame에 새로운 컬럼 추가
  • DataFrame['컬럼명'] = 데이터
  • 데이터의 개수는 기존 다른 컬럼의 행 개수와 같아야 함
# [4-11] bread의 '소재지전체주소'에서 '구명', '동명'을 추출하여 
# bread에 새로운 컬럼으로 등록합니다.
bread['구명'] = bread['소재지전체주소'].str.split().str[1]
bread['동명'] = bread['소재지전체주소'].str.split().str[2]
# bread의 컬럼명을 출력해 '구명', '동명'이 추가되었는지 확인함
bread.columns

 

7. 결측치 확인/처리

결측치는 값이 없음을 나타냄
  • NaN, NaT, None 등으로 표기되며, NA Value, Missing Value 라고 함
결측치 확인
  • DataFrame.isna() : 결측치에 대해 True, 아니면 False
  • DataFrame.isnull() : DataFrame.isna()와 동일함
  • DataFrame.notna() : 결측치가 아닌 것에 대해 True, 결측치면 False
  • DataFrame.notnull() : DataFrame.isnull()과 동일함
  • Series에도 결측치 확인을 위한 isna() ~ notnull()의 메서드 있음
DataFrame.isna().sum() : 결측치에 대해 컬럼별 개수
# [4-12] bread2의 각 컬럼별 결측치의 개수를 확인합니다.
bread.isna().sum()
bread[bread['폐업일자'].isna()]

 

8. 결측치 채우기

결측치 채우기
  • DataFrame.fillna(값) : 결측치를 특정 값으로 채움
데이터 타입 변경 방법
  • Series.astype(타입)
  • 타입 표시 방법 : 'int', 'int32', 'int64', 'float', 'str', 'category', ... 등의 문자열로 지정
  • np.int16, np.float32, np.datetime64, ... 등의 numpy 타입으로 지정
  • numpy 타입으로 지정하기 위해서는 import numpy as np 를 먼저 실행하여야 함
# [4-13] bread2의 '폐업일자'에 대해 결측치인 것을 0.0으로 채우기 한 뒤, 
# 데이터 타입을 'int64'로 수정합니다.
bread['폐업일자'] = bread['폐업일자'].fillna(0.0).astype('int64')
# [4-14] bread의 전체 결측치의 개수를 하나의 정수로 확인합니다.
bread.isna().sum().sum()
bread.isna().any() # any : 하나의 결측치라도 있으면 True, 하나도 없으면 False

 

9. 컬럼 제거

  • DataFrame.drop(columns=['컬럼명1', '컬럼명2', ...])
  • DataFrame.drop(['컬럼명1', '컬럼명2', ...], axis=1)
# [4-15] bread2에서 '소재지전체주소' 및 '업태구분명' 컬럼을 제거한 뒤, shape을 확인합니다.
bread = bread.drop(columns=['소재지전체주소''업태구분명'])
bread.shape
#bread.drop(['소재지전체주소','업태구분명'], axis=1)
# [4-16] bread2의 첫 3개 행을 확인합니다.
bread.head(3)

 

10. 컬럼 이름 변경하기

  • DataFrame.rename(columns={'변경전이름':'변경후이름', ...})
  • DataFrame.rename({'변경전이름':'변경후이름', ...}, axis=1)
# [4-17] bread2의 '상세영업상태코드'라는 컬럼명을 '상태코드'로 변경한 뒤,
# 첫 2개의 행을 확인합니다.
bread = bread.rename(columns={'상세영업상태코드':'상태코드'})
#bread.rename({'상세영업상태코드':'상태코드'}, axis=1)
bread.head(2)

 

11. csv 파일로 저장하기

  • DataFrame.to_csv('파일이름', index=False) : index를 제외한 내용을 csv 파일로 저장함
# [4-18] bread2를 'bread_after.csv' 파일로 index를 제외하고 저장합니다.
bread.to_csv('bread_after.csv', index=False)
# [4-19] 'bread_after.csv' 파일을 읽어 bread라는 이름으로 저장합니다.
bread = pd.read_csv('bread_after.csv')
bread.head(2)

 

12. Series의 연산

  • Series는 스칼라값과 연산 시 각 값과 스칼라 값의 연산이 이루어짐
  • 결과는 Series가 됨
# [4-20] bread에 '설립년도' 및 '폐업년도' 컬럼을 추가합니다.
# '인허가일자'//10000, '폐업일자 // 10000 을 사용하여 구합니다.
# 두 개의 컬럼이 추가된 bread의 첫 2개 행을 확인합니다.
year = bread['인허가일자'] // 10000
month = bread['인허가일자'] // 100 % 100
day = bread['인허가일자'] % 100
bread['설립년도'] = bread['인허가일자']//10000
bread['폐업년도'] = bread['폐업일자']//10000
bread.tail(2)
pd.to_datetime(bread['인허가일자'], format='%Y%m%d')

# [4-21] bread에 '영업기간' 컬럼을 추가합니다
# '영업기간'은 '상태코드'가 1(=영업)인 경우 2021 - 설립년도 -1
# '상태코드'가 2(=폐업)인 경우 폐업년도 - 설립년도 + 1로 계산합니다.
bread.loc[bread['상태코드']==1'영업기간'] = 2021 - bread['설립년도']+1
bread.loc[bread['상태코드']==2'영업기간'] = bread['폐업년도']-bread['설립년도']+1
bread.tail(3)

# 현재 날짜 정보 알아오기
from datetime import datetime
today = datetime.today()
print(today)
print(today.year, today.month, today.day)

 

13. Series->DataFrame, 전치행렬 구하기

Series를 DataFrame으로 만들기
  • pd.DataFrame(Series)
  • Series.to_frame()
DataFrame의 index 정렬하기
  • DataFrame.sort_index() : 오름차순 정렬
  • DataFrame.sort_index(ascending=False) : 내림차순 정렬
DataFrame의 전치행렬 구하기
  • DataFrame.T
# [4-22] bread의 '설립년도'별 데이터 수를 구해 년도별로 정렬하고, 
# DataFrame으로 변경하여 전치행렬을 구해 temp1 이름을 부여해 출력합니다.
temp1= bread['설립년도'].value_counts().sort_index().to_frame().T
temp1

# [4-23] bread의 '폐업년도'별 데이터 수를 구해 년도별로 정렬하고, 
# DataFrame으로 변경하여 전치행렬을 구해 temp2 이름을 부여해 출력합니다.
temp2= bread['폐업년도'].value_counts().sort_index().to_frame().T
temp2

 

14. 여러 개의 데이터프레임 합치기

  • pd.concat([DataFrame1, DataFrame2, ...])
  • DataFrame의 목록에 있는 순서대로 위 -> 아래 방향으로 합쳐 한 개 DataFrame 반환
# [4-23] temp1, temp2를 합쳐서 temp라고 이름 붙입니다.
temp = pd.concat([temp1,temp2])
# [4-24] temp의 결측치를 0으로 채우기 한 뒤, 'int64'로 변경합니다.
temp.fillna(0).astype('int64')

 

15. 문자열(contains) 함수

특정 문자열이 포함된 행 가져오기
  • Series.str.contains(문자열) : 문자열이 포함된 행은 True, 아니면 False인 Series 반환
  • DataFrame.loc[조건, :] : 조건이 True인 행만 가져오기
# [4-26] bread에서 '사업장명' 컬럼을 사용하여 
# '파리바게트', '파리바게뜨' 이름인 곳을 뽑아 paris로 이름 붙입니다.
paris = bread.loc[bread['사업장명'].str.contains('파리바게'),:]
paris.head(3)
# [4-27] bread에서 '사업장명' 컬럼을 사용하여 
# '뚜레쥬르' 이름인 곳을 뽑아 tous로 이름 붙입니다.
tous = bread.loc[bread['사업장명'].str.contains('뚜레쥬르'),:]
tous.head(3)

 

16. 통계함수

  • Series.count() : 개수
  • Series.sum() : 합계
  • Series.mean() : 평균
  • Series.std() : 표준편차
  • Series.var() : 분산
  • Series.median() : 중앙값
  • Series.mode() : 최빈값
  • Series.cumsum() : 누적합
  • Series.quantile([0.25, 05, 0.75]) : 분위수
# [4-28] 설립년도가 2000년 이후이면서 영업 중인 곳의 영업기간 정보를 구합니다.
# paris, tous에 대해 각각 구해서 temp1, temp2로 이름 붙입니다.
temp1 = paris.loc[(paris['설립년도']>2000) & (paris['상태코드']==1),'영업기간']
temp1
temp2 = tous.loc[(tous['설립년도']>2000) & (tous['상태코드']==1),'영업기간']
temp2
# temp1, temp2의 평균을 구해 이름을 comp로 하는 DataFrame으로 만듭니다. 
# index => ['파리바게트', '뚜레쥬르'], columns => ['영업']
s = pd.Series([temp1.mean(), temp2.mean()], index=['파리바게트''뚜레쥬르'])
comp = pd.DataFrame(s, columns=['영업'])
comp

# [4-30] 파리바게트, 뚜레쥬르가 아닌 다른 사업장에 대한 정보를 찾아 other로 이름 붙입니다.
condition1 = bread['사업장명'].str.contains('파리바게')
condition2 = bread['사업장명'].str.contains('뚜레쥬르')

other = bread.loc[-(condition1 | condition2),:]
# other의 행, 열 정보를 확인합니다.
other.shape

# [4-31] other의 2000년 이후 설립된 곳의 영업, 폐업 사업장을 구한 뒤 
# temp1, temp2 이름을 붙입니다.
temp1 = other.loc[(other['설립년도']>2000) & (other['상태코드']==1),'영업기간']
temp2 = other.loc[(other['설립년도']>2000) & (other['상태코드']==2),'영업기간']

# temp1, temp2의 평균을 구해 comp 에 '나머지' 행으로 추가합니다.
temp = pd.DataFrame([[temp1.mean(), temp2.mean()]], index=['나머지'], columns=['영업''폐업'])
comp = comp.append(temp)
comp

 

17. restet index

# [4-32] paris에서 영업 중인 곳에 대해 '시군구명'별 개수를 구해 DataFrame으로 변환하고
# temp로 이름 붙인 뒤, 첫 2개 행을 출력한다
temp = paris.loc[paris['상태코드']==1,'구명'].value_counts().to_frame()
temp.head(2)
DataFrame.reset_index() : index의 내용을 columns로 이동함


 [4-33] paris에서 폐업한 곳에 대해 '구명'별 개수를 구해 
# temp에 '폐업'이라는 컬럼으로 추가하고,
# reset_index()를 사용하여 index를 columns로 사용되도록 한다. (temp2로 다시 저장)
temp['폐업'] = paris.loc[paris['상태코드']==2,'구명'].value_counts()
temp2 = temp.reset_index()
temp2.head(2)

 

18. 컬럼 이름 변경

DataFrame의 모든 컬럼이름 변경
  • DataFrame.columns = [컬럼이름1, 컬럼이름2, ...]
  • 기존 컬럼의 개수와 같아야 함
# [4-34] temp2의 컬럼명을 ['구', '영업', '폐업']으로 변경한다
temp2.columns=['구''영업''폐업']

# temp2의 첫 2개 행을 출력한다
temp2.head(2)

# [4-35] temp2에 '폐업비율' 컬럼을 추가한다
# 폐업비율 = 폐업 / (폐업 + 영업) * 100
temp2['폐업비율'] = (temp2['폐업'] / (temp2['폐업']+temp2['영업']))*100
# temp2의 첫 3개 행을 출력한다
temp2.head(3)

 

19. 데이터 정렬

  • DataFrame.sort_values('컬럼이름') : 주어진 컬럼을 기준으로 데이터를 오름차순 정렬
  • DataFrame.sort_values('컬럼이름', ascending=False) : 내림차순 정렬
  • DataFrame.sort_values(['컬럼이름1', '컬럼이름2'..]) : 다차 정렬
# [4-36] temp2를 폐업비율을 기준으로 오름차순 정렬하여 TOP5를 출력한다
# 폐업비율이 가장 작은 곳은 은평구, 동대문구 ... 등으로 정보를 찾게 됨
temp2.sort_values('폐업비율').head(5)

 

20. 사분위수(quantile)

Series.quantile([rate1, rate2, ...])
  • 데이터를 순서대로 나열했을 때, 특정 비율 위치의 값을 구함
  • 0 : 가장 작은 것의 값
  • 1 : 가장 큰 것의 값
Series.quantile([0.3, 0.9])
  • 0.3 : 하위 30% 위치
  • 0.9 : 상위 10% 위치
# [4-37] temp에서 폐업비율 하위 30%인 곳을 구하시오.
value = temp2['폐업비율'].quantile(0.3)
temp2.loc[temp2['폐업비율']<=value,]
# [4-38] temp에서 폐업비율 상위 20%인 곳을 구하시오.
value = temp2['폐업비율'].quantile(0.8)
temp2.loc[temp2['폐업비율']>=value,]

 

출처 : 유튜브 강의 EduAtoZ