본문 바로가기
study/Python

[Python] 40. age.csv 파일을 읽어서 인구구조를 알고 싶은 동을 찾아서 인구구조 그래프를 작성하기, 데이터 전처리 : 원본데이터를 원하는 형태로 변경하는 과정, 중복데이터 처리

by 금이패런츠 2022. 6. 29.
728x90
반응형

1. age.csv 파일을 읽어서 인구구조를 알고 싶은 동을 찾아서 인구구조 그래프를 작성하기

2. 데이터 전처리 : 원본데이터를 원하는 형태로 변경하는 과정

3. 중복데이터 처리

# -*- coding: utf-8 -*-
"""
Created on Wed Jun 29 09:27:45 2022

@author: p011v
"""

'''
    -- 행정안전부 홈페이지 : www.mois.go.kr
        -> 정책자료 -> 주민등록인구통계 -> 연령별인구현황
        -> 계:선택, 남여구분:선택안함
        -> 연령 구분 단위 : 1세
        -> 만 연령구분 : 0세 ~ 100세이상 -> 검색버튼클릭
        -> 전체읍면동현황 선택
        -> csv 파일로 다운받기 (age.csv 파일로 이름 변경)
    -- age.csv파일 data폴더에 저장하기 (data폴더 생성)
'''
########## 1. age.csv 파일을 읽어, 인구구조알고 싶은 동을 찾아서 인구구조 그래프를 작성하기
import numpy as np
import csv
import matplotlib.pyplot as plt
f = open("data/age.csv")
data = csv.reader(f) #csv 형태의 파일을 읽어 저장
type(data)
data
name="역삼"
for row in data : #data를 읽은 이후부터 읽기
    if row[0].find(name) >= 0 :
        print(row)
        #(lambda x:x.replace(",","")) : ,문자를 제거
        row = list(map((lambda x:x.replace(",","")), row))
        print(row)
        # row 데이터의 3번인덱스 이후 부터를 배열 생성
        home = np.array(row[3:], dtype=int)
        break
    
plt.style.use('ggplot')
plt.figure(figsize=(10, 5), dpi=100)
plt.rc('font', family="Malgun Gothic")
plt.title(name + ' 지역의 인구 구조')
plt.plot(home)

# 같은 이름을 포함한 동이 있는 경우 모든 동을 그래프로 작성하기
# data : 리스트객체로 변경. 항상 처음부터 읽기
f = open("data/age.csv")
data = csv.reader(f) #csv 형태의 파일을 읽어 저장
next(data) #header 정보 skip. 한줄 읽기.
data = list(data) #파일스트림 데이터를 리스트객체로 변경. [[], [], ...]
name = "역삼"
homelist = [] #데이터저장
namelist = [] #동이름저장

# 문제 : 동 이름에서 코드값을 제거하기
import re
for row in data : #data를 읽은 이후부터 읽기
    if row[0].find(name) >= 0 :
        row = list(map((lambda x:x.replace(",","")), row)) #, 값을 제거
        homelist.append(np.array(row[3:], dtype=int)) #name에 해당하는 인구정보 데이터 추가
#       namelist.append(row[0]) #선택된 데이터 동의 이름 추가
#       namelist.append(row[0][:row[0].find('(')]) #선택된 데이터 동의 이름 추가 (제외)
        namelist.append(re.sub('\(\d*\)', '', row[0]))
'''
    re.sub(패턴, 치환문자, 대상문자열)
    \(\d*\) : \( 문자, \) 문자, (): 그룹패턴표현
              \d* : \d : 숫자. *:0개이상. => 숫자여러개. 0개이상의 숫자
'''        
plt.style.use('ggplot')
plt.figure(figsize=(10, 5), dpi=100)
plt.rc('font', family="Malgun Gothic")
plt.title(name + ' 지역의 인구 구조')
for h, n in zip(homelist, namelist) :
    # h : 인구 정보 리스트 데이터
    # n : 이름 데이터
    plt.plot(h, label = n)
plt.legend()

# age.csv 파일을 이용해서 선택한 지역의 인구구조와,
# 가장 비슷한 인구구조를 가진 지역의 그래프와 지역을 출력하기.
# 선택한 지역은 한개만 가능하도록 한다.
import numpy as np
import csv
import matplotlib.pyplot as plt

f=open('data/age.csv')
data=csv.reader(f)
next(data)
data=list(data)
name='무거동'
for row in data:
    if name in row[0] : #name 이 row[0] 포함?
        row = list(map((lambda x:x.replace(",","")), row)) #, 부분 제거
        #row[2]: 해당 지역의 전체 인구수. 
        # 나이가 전체 인구수 대비 비율
        home = np.array(row[3:],dtype=int) / int(row[2])
        home_name = re.sub("\(\d*\)", "", row[0]) #(코드) 부분 제거
        
mn=1
for row in data:
    row = list(map((lambda x:x.replace(",","")), row))
    away = np.array(row[3:], dtype=int) /int(row[2]) #인구 비율
    # s : 해당 지역과 다른 지역의 차이 값. s의 값과 인구비율은 반비례. 0에 가까울수록 비슷한 지역
    s = np.sum((home-away) **2) #(지역비율 - 다른지역비율) ** 2
    if s < mn and name not in row[0] : # 다른지역이면서, s값이 작은 지역을 찾기
        mn = s
        result_name = re.sub('\(\d*\)', '', row[0])
        result = away

#result_name : home지역과 가장 인구비율이 비슷한 지역의 이름 저장
#result : home지역과 가장 인구비율이 비슷한 지역의 데이터 저장
        
plt.style.use('ggplot')
plt.figure(figsize = (10,5), dpi=100)
plt.rc('font', family = 'Malgun Gothic')
plt.title(name  + ' 지역과 가장 비슷한 인구 구조를 가진 지역')
plt.plot(home, label = home_name)
plt.plot(result, label = result_name)
plt.legend()
plt.show()

# 설정된 지역과 가장 비슷한 인구 비율 가진 지역을 그래프로 표시하기
# 판다스로 변경하기
import pandas as pd
#age.csv : 인코딩방식 cp949. 기본코딩방식.  파일로 read시 인코딩 방식. ANSI형식
#    pandas 데이터의 기본 인코딩은 utf-8 => pandas로 데이터 read시 utf-8이 아닌 경우 encoding을 설정해야함.
# index_col=0 : 0번 컬럼을 인덱스로 설정
# thousands="," : 숫자가 세자리마다 ','가 있는 경우 숫자로 인식
df = pd.read_csv("data/age.csv", encoding="cp949", index_col=0, thousands=",")
df.info()
df.head()

col_name=['총인구수', '연령구간인구수']
for i in range(0, 101) : # 0 ~ 100
    col_name.append(str(i) + '세')
col_name
# df데이터의 컬럼명 변경
df.columns = col_name
df = df.div(df["총인구수"], axis=0)
# 총인구수로 모든 컬럼들을 나누기. 비율로 저장.
df.head()
#총인구수, 연령구간인구수 컬럼 제거
del df['총인구수'], df['연령구간인구수']
df.info()
df.count() #결측값 존재 확인.
# fillna : 결측값을 다른값으로 치환
df.fillna(0, inplace=True) #df 데이터의 결측값을 0으로 채움
name = "역삼2동" #선택된 동
'''
    df.index : 행정구역 이름. 동이름
    df.index.str : 인덱스의 이름을 문자열(str)로 변경
    df.index.str.contains(name) : 선택된 동이름을 포함하고 있는 인덱스의 이름만 결과값이 True
'''
a = df.index.str.contains(name)
a
df2 = df[a] #선택된 동이름을 가진 레코드만 저장
df2
# b : a값을 True와 False 변경. 선택된 동이름의 데이터만 제외한 다른 데이터들만 True
b = list(map((lambda x : not x), a))
b
df3 = df[b] #선택된 동이름이 없는 레코드만 저장. df2와 반대
df3.head()
mn = 1
#df3.T : 전치행렬. 행과 열을 바꿈
df3.T
for label, content in df3.T.items() :
    s = sum((content - df2.iloc[0]) **2)
    if s < mn :
        mn = s
        result = content #인구비율
        result_name = label #동의 이름
df2.T.plot() #선택된 데이터를 그래프로 작성
result.plot(legend = result_name)
plt.legend()
plt.show()


########## 2. 데이터 전처리 : 원본데이터를 원하는 형태로 변경하는 과정
#innull, notnull, dropna, fillna
import seaborn as sns
df = sns.load_dataset("titanic")
df.info()
# deck 컬럼의 값의 종류 출력하기
df.deck
df.deck.unique()
# deck 컬럼의 값의 갯수 출력하기
df.deck.value_counts()
# deck 컬럼의 값을 결측값을 포함한 갯수 출력하기
df.deck.value_counts(dropna=False)

# innull() : 결측값인 경우 True 반환
df.deck.head()
df.deck.head().isnull()
# notnull() : 결측값인 경우 False 반환
df.deck.head().notnull()

# 결측값의 컬럼별 갯수 조회하기
df.isnull().sum()
df.isnull().sum(axis=0) #행을 기준으로 결측값의 컬럼별 갯수 조회
df.isnull().sum(axis=1) #열을 기준으로 결측값의 컬럼별 갯수 조회

# 결측값이 아닌 갯수 조회하기
df.notnull().sum()
df.notnull().sum(axis=0) #행을 기준으로 결측값의 컬럼별 갯수 조회
df.notnull().sum(axis=1) #열을 기준으로 결측값의 컬럼별 갯수 조회

# dropna 함수 : 결측값을 제거시 사용되는 함수. inplace=True가 없으면 자체 변경 안됨
# 결측값이 500개 이상인 컬럼 제거하기
# thresh=500 : 결측값이 500개 이상인 경우
df_thresh = df.dropna(axis=1, thresh=500)
df_thresh.info()
df.info()

# 결측값을 가진 행을 제거
# subset=["age"] : 컬럼
# how='any'/'all' : 한개만 결측값 / 모든값이 결측값
# axis=0 : 행
df_age = df_thresh.dropna(subset=["age"], how='any', axis=0)
df_age.info()

# fillna : 결측값을 다른값으로 치환
#     fillna(치환값, 옵션)
# option : inplace=True : 객체 자체 변경
df.info()
# age 컬럼의 값이 결측값인 경우 평균나이로 변경하기
# 1. age 컬럼의 평균값 조회하기
age_maen = df["age"].mean() #age_maen = df.age.mean()
age_maen

df["age"].fillna(age_maen, inplace=True)
df.info()
df.mean()["age"]

# embark_town 컬럼의 결측값을 빈도수가 가장 많은 데이터로 치환하기
# embark_town 컬럼의 데이터별 건수 조회하기. 결측값도 포함
most_freq = df["embark_town"].value_counts(dropna=False)
# 1. Series.idxmax() : 가장 큰 값을 가진 인덱스
most_freq = df["embark_town"].value_counts(dropna=False).idxmax()
type(most_freq)
most_freq

# 2. embark_town 컬럼 결측값인 행을 조회하기
df[df["embark_town"].isnull()]
df.iloc[[61, 829]]

# 3. embark_town 컬럼의 결측값을 빈도수가 가장 많은 데이터로 치환하기
df["embark_town"].fillna(most_freq, inplace=True)
df.info()
df.iloc[[61, 829]]["embark_town"]

# embarked 컬럼을 앞의 값으로 치환하기.
# 1. 결측값 레코드 조회하기
df[df["embarked"].isnull()]
df.iloc[[61, 829]]["embarked"] 
# 61 인덱스의 앞의 데이터 조회
df["embarked"][58:62] # 60번 인덱스 : C
# 829 인덱스의 앞의 데이터 조회
df["embarked"][825:830] # 828번 인덱스 : Q

# 2. 61 : C, 829 : Q로 치환하기
# method="ffill" : 앞의 데이터
#       "backfill","bfill : 뒤의 데이터 치환
df["embarked"].fillna(method="ffill", inplace=True)
df.iloc[[61, 829]]["embarked"] 

########## 3. 중복데이터 처리
df = pd.DataFrame({"c1":['a','a','b','a','b'],
                   "c2":[1,1,1,2,2],
                   "c3":[1,1,2,2,2]})
df

# duplicated() : 중복데이터 찾기. 중복된 경우 두번 행의 결과만 True로 리턴.
#                전체 행을 기준으로 검색
df_dup = df.duplicated()
df_dup
df[df_dup]
# c1 컬럼을 기준으로 중복 검색
col_dup = df["c1"].duplicated()
col_dup
df[col_dup]

# df 데이터 중 중복데이터 제거하기
# drop_duplicates() : 중복된 행을 제거하기
df
df2 = df.drop_duplicates()
df2

# c1, c3 컬럼을 기준으로 중복 검색
col_dup = df[["c1","c3"]].duplicated()
col_dup
df[col_dup]

# c1, c3 컬럼을 기준으로 중복 제거하기
df3 = df.drop_duplicates(subset=["c1", "c3"])
df3

# mpg 데이터 조회하기
import seaborn as sns
#mpg = sns.load_dataset("mpg")

mpg = pd.read_csv("data/auto-mpg.csv")
mpg.info()

'''
    mpg   :  연비. mile per gallon
    cylinders : 실린더 수
    displacement : 배기량
    horsepower : 출력
    weight : 차량무게
    acceleration : 가속능력
    model year : 출시년도
    origin : 제조국
    name : 모델명

'''
# 새로운 컬럼 생성하기
# kpl 컬럼 추가
# kpl : kilometer per liter. mpg * 0.425
mpg['kpl'] = mpg['mpg'] * 0.425
mpg.info()
mpg['kpl'].head(10)
mpg['mpg'].head(10)

# kpl컬럼의 데이터를 소숫점 1자리로 변경하기. 반올림하기
# round(1) : 반올림함수. 소숫점 1 자리로 변경
mpg['kpl'] = mpg['kpl'].round(1)
mpg['kpl'].head(10)

mpg.info()

#horsepower 컬럼의 값을 조회하기
mpg.horsepower.unique()
mpg[['mpg','horsepower']].describe()

#오류데이터('?') 처리.
# replace 함수: 결측값 변경
# replace(원본문자,치환문자,inplace=True)
# np.nan: 결측값
mpg['horsepower'].replace('?', np.nan, inplace=True) #? 문자를 결측값 치환
mpg.info()
# horsepower 컬럼의 값이 결측값인 행을 조회하기
mpg[mpg['horsepower'].isnull()]
mpg.iloc[[32, 126, 330, 336, 354, 374]]["horsepower"]
# horsepower 컬럼의 값이 결측값인 경우 레코드 제거하기
mpg.dropna(subset=["horsepower"], axis=0, inplace=True)
mpg.info()
# 자료형을 실수형으로 변환하기
# astype(자료형) : 자료형으로 변환. 요소들의 자료형을 변환.
mpg["horsepower"] = mpg["horsepower"].astype("float")
mpg.info()
728x90
반응형

'study > Python' 카테고리의 다른 글

[Python] 40. Test 답  (0) 2022.06.29
[Python] 40. Test  (0) 2022.06.29
[Python] 39. Test 답  (0) 2022.06.28
[Python] 39. Test  (0) 2022.06.28
[Python] 39. numpy  (0) 2022.06.28