황규진 2024. 7. 9. 16:10

Merge_Concat

두 데이터 프레임 연결하기

import pandas as pd
df1 = pd.DataFrame({
    'id': [1, 2, 3],
    'customer_id': [1, 2, 3],
    'customer_name': ['Robert', 'Peter', 'Dave']
}, columns=['id', 'customer_id', 'customer_name'])
df1

df2 = pd.DataFrame({
    'id': [1, 2, 4],
    'order_id': [100, 200, 300],
    'order_date': ['2021-01-21', '2021-02-03', '2020-10-01']
}, columns=['id', 'order_id', 'order_date'])
df2

concat()

  • 두 데이터프레임을 연결해서 하나의 데이터프레임으로 만들 수 있음
  • 두 데이터프레임을 위/아래 또는 왼쪽/오른쪽으로 연결하기만 함
  • pd.concat([데이터프레임1, 데이터프레임2])
pd.concat([df1, df2])

axis: 0 이면(디폴트) 위에서 아래로 합치고, 1 이면 왼쪽과 오른쪽으로 합침

doc = pd.concat([df1, df2], axis=1)
doc.head()

 

두 데이터 프레임 합치기

merge()

  • merge(데이터프레임1, 데이터프레임2) : 두 데이터프레임에 동일한 이름을 가진 컬럼을 기준으로 두 데이터프레임을 합침
pd.merge(df1, df2)

  • merge(데이터프레임1, 데이터프레임2, on=기준컬럼명) : 기준 컬럼을 명시할 수도 있음
pd.merge(df1, df2, on='id')

merge() 를 통해 어떻게 두 데이터프레임을 결함시킬 것인가에 대해 보다 상세한 기능을 제공함

  • merge(데이터프레임1, 데이터프레임2, how=결합방법)
  • 결합방법
    1. inner : 내부 조인 - SQL의 INNER JOIN 과 동일
    2. outer : 완전 외부 조인 - SQL의 OUTER JOIN 과 동일
    3. left : 왼쪽 우선 외부 조인 - SQL의 LEFT OUTER JOIN 과 동일
    4. right : 오른쪽 우선 외부 조인 - SQL의 RIGHT OUTER JOIN 과 동일

merge() 함수는 SQL의 JOIN 기능과 동일함

  • SQL JOIN: 두 개 이상의 테이블로부터 필요한 데이터를 연결해 하나의 포괄적인 구조로 결합시키는 연산

1. inner : 내부 조인 - SQL의 INNER JOIN 과 동일 (디폴트)

  • 동작 방식
    1. on의 컬럼값이 두 데이터프레임에서 동일한 행 찾기
    2. 각 동일한 행의 컬럼/컬럼값만 가져오기

2. outer : 완전 외부 조인 - SQL의 OUTER JOIN 과 동일

  • 동작 방식
    1. on의 컬럼값이 두 데이터프레임에서 동일한 행 찾기
    2. 각 동일한 행의 컬럼/컬럼값 가져와 붙이기
    3. 각 데이터프레임에서 on의 컬럼값이 다른 나머지 행을 찾기
    4. 각 나머지 행의 컬럼/컬럼값을 가져와 별도 행으로 붙이기
      • 두 데이터프레임 각각에만 있는 컬럼이어서, 컬럼값이 없을 경우 데이터 없음(NaN)으로 표기하기

3. left : 왼쪽 우선 외부 조인 - SQL의 LEFT OUTER JOIN 과 동일

  • 동작 방식
    1. 왼쪽 데이터프레임의 행을 모두 가져오기
    2. 왼쪽 데이터프레임의 행에 있는 on의 컬럼값이 동일한 오른쪽 데이터프레임의 행만 컬럼과 함께 가져와 붙이기
    3. 오른쪽 데이터프레임에 없는 on의 컬럼값을 가진 왼쪽 데이터프레임의 오른쪽 데이터프레임 컬럼들에는 데이터 없음(NaN)으로 표기하기

4. right : 오른쪽 우선 외부 조인 - SQL의 RIGHT OUTER JOIN 과 동일

  • 동작 방식
    1. 오른쪽 데이터프레임의 행을 모두 가져오기
    2. 오른쪽 데이터프레임의 행에 있는 on의 컬럼값이 동일한 왼쪽 데이터프레임의 행만 컬럼과 함께 가져와 붙이기
    3. 왼쪽 데이터프레임에 없는 on의 컬럼값을 가진 오른쪽 데이터프레임의 왼쪽 데이터프레임 컬럼들에는 데이터 없음(NaN)으로 표기하기

컬럼이 아닌 인덱스를 기준 컬럼으로 사용하기

  • merge(데이터프레임1, 데이터프레임2, left_index=True, right_index=True) : 기준 컬럼을 명시할 수도 있음
### 사전 선언
import pandas as pd
df1 = pd.DataFrame({
    'id': [1, 2, 3],
    'customer_id': [1, 2, 3],
    'customer_name': ['Robert', 'Peter', 'Dave']
}, columns=['id', 'customer_id', 'customer_name'])
df2 = pd.DataFrame({
    'id': [1, 2, 4],
    'order_id': [100, 200, 300],
    'order_date': ['2021-01-21', '2021-02-03', '2020-10-01']
}, columns=['id', 'order_id', 'order_date'])
df1 = df1.set_index('id')
df1

df2 = df2.set_index('id')
df2

pd.merge(df1, df2, left_index=True, right_index=True)

pd.merge(df1, df2, how='outer', left_index=True, right_index=True)

 

raw data를 pandas와 파이썬으로 그래프 생성

1. 데이터 시각화란?

  • 데이터 분석 결과를 쉽게 이해할 수 있도록 시각적으로 표현하고 전달되는 과정
  • 탐색적 데이터 분석, 데이터 처리, 데이터 예측 모든 경우, 결과를 알아보기 쉽게 하기 위해 데이터 시각화는 필수적임
  • 다양한 시각화 기법 중, 가장 최신의 흥미로운 데이터 시각화 과정을 진행해보기로 함

지금까지 익힌 데이터 처리 기술을 기반으로 데이터 시각화를 위해, raw data를 포멧에 맞추어 변환하여 그래프를 만들어보기

2. 데이터 시각화를 위한 데이터 포멧 이해

  • 데이터 시각화를 위해, raw data를 변환해야 함
  • 지금까지 익힌 데이터 처리 기술을 사용해서, 데이터를 변환하기로 함
  • 필요 데이터
    • 국가명, 국기, 날짜별 확진자 수

 

3. raw data 가져오기

import pandas as pd
PATH = "COVID-19-master/csse_covid_19_data/csse_covid_19_daily_reports/"
doc = pd.read_csv(PATH + "04-01-2020.csv", encoding='utf-8-sig')
doc.head()

import pandas as pd
PATH = "COVID-19-master/csse_covid_19_data/csse_covid_19_daily_reports/"
doc = pd.read_csv(PATH + "03-01-2020.csv", encoding='utf-8-sig')
doc.head()

  • 3월 중순 데이터까지는 컬럼명이 Province/State, Country/Region 이고, 이후에는 Province_State, Country_Region 이므로, try except 구문을 사용해서, 데이터 조작
doc = pd.read_csv(PATH + "01-22-2020.csv", encoding='utf-8-sig')
try:
    doc = doc[['Province_State', 'Country_Region', 'Confirmed']]  # 1. 특정 컬럼만 선택해서 데이터프레임 만들기
except:
    doc = doc[['Province/State', 'Country/Region', 'Confirmed']]  # 1. 특정 컬럼만 선택해서 데이터프레임 만들기
    doc.columns = ['Province_State', 'Country_Region', 'Confirmed']
    
doc.head()

 

4. 데이터프레임 데이터 변환

  1. 특정 컬럼만 선택해서 데이터프레임 만들기
  2. 특정 컬럼에 없는 데이터 삭제하기
  3. 특정 컬럼의 데이터 타입 변경하기
import pandas as pd
PATH = "COVID-19-master/csse_covid_19_data/csse_covid_19_daily_reports/"

doc = pd.read_csv(PATH + "01-22-2020.csv", encoding='utf-8-sig')
try:
    doc = doc[['Province_State', 'Country_Region', 'Confirmed']]  # 1. 특정 컬럼만 선택해서 데이터프레임 만들기
except:
    doc = doc[['Province/State', 'Country/Region', 'Confirmed']]  # 1. 특정 컬럼만 선택해서 데이터프레임 만들기
    doc.columns = ['Province_State', 'Country_Region', 'Confirmed']
doc = doc.dropna(subset=['Confirmed'])     # 2. 특정 컬럼에 없는 데이터 삭제하기
doc = doc.astype({'Confirmed': 'int64'})   # 3. 특정 컬럼의 데이터 타입 변경하기
doc.head()

  • 국가 정보 가져오기
country_info = pd.read_csv("COVID-19-master/csse_covid_19_data/UID_ISO_FIPS_LookUp_Table.csv", encoding='utf-8-sig')
country_info.head()

  • 두 데이터프레임 합쳐보기
test_df = pd.merge(doc, country_info, how='left', on='Country_Region')
test_df.head()

  • 잘못 매칭된 국가 정보 확인하기

    • iso2 컬럼이 매칭되지 않은 확진자수 국가 확인해보기
    test_df.isnull().sum()

nan_rows = test_df[test_df['iso2'].isnull()]
nan_rows.head()

컬럼값 변경하기

  • Country_Region 국가 명이 다양한 경우가 많았음
  • 각 케이스를 일괄적으로 변경할 키 값이 존재하지 않고, 키가 될 수 있는 컬럼도 다양하고, 각 파일마다 키가 될 수 있는 컬럼이 변경되어, 키 값으로 매칭이 불가 하였음
  • 이에 각 케이스를 직접 확인해서, 국가 명을 일관되게 변경할 수 있도록 별도 json 파일 작성
  • json 파일 기반으로 국가 명을 일관되게 변경하기로 함

json.load() 함수로 파일로 된 json 데이터를 사전처럼 다룰 수 있음

import json

with open('COVID-19-master/csse_covid_19_data/country_convert.json', 'r', encoding='utf-8-sig') as json_file:
    json_data = json.load(json_file)
    print (json_data.keys())

apply() 함수 사용법

  • apply() 함수를 사용해서, 특정 컬럼값 변경 가능
df = pd.DataFrame({
    '영어': [60, 70],
    '수학': [100, 50]
}, index = ['Dave', 'David'])
df

def func(df_data):
    print (type(df_data))    
    print (df_data.index)
    print (df_data.values)    
    return df_data
df_func = df.apply(func, axis=0)

df_func = df.apply(func, axis=1)

df = pd.DataFrame({
    '영어': [60, 70],
    '수학': [100, 50]
}, index = ['Dave', 'David'])
df

def func(df_data):
    df_data['영어'] = 80
    return df_data

df_func = df.apply(func, axis=1)
df_func

apply() 함수를 사용해서, 국가 컬럼값 변경하기

  • 사전 작업 (doc 변수로 데이터프레임 파일 만들기)
import pandas as pd

doc = pd.read_csv(PATH + "01-22-2020.csv", encoding='utf-8-sig')
try:
    doc = doc[['Province_State', 'Country_Region', 'Confirmed']]  # 1. 특정 컬럼만 선택해서 데이터프레임 만들기
except:
    doc = doc[['Province/State', 'Country/Region', 'Confirmed']]  # 1. 특정 컬럼만 선택해서 데이터프레임 만들기
    doc.columns = ['Province_State', 'Country_Region', 'Confirmed']
doc = doc.dropna(subset=['Confirmed'])     # 2. 특정 컬럼에 없는 데이터 삭제하기
doc = doc.astype({'Confirmed': 'int64'})   # 3. 특정 컬럼의 데이터 타입 변경하기
doc.head()

  • 변경할 국가명을 가지고 있는 json 파일 읽기
import json

with open('COVID-19-master/csse_covid_19_data/country_convert.json', 'r', encoding='utf-8-sig') as json_file:
    json_data = json.load(json_file)
    print (json_data.keys())

  • Country_Region 이라는 컬럼값을 확인해서, 국가명이 다르게 기재되어 있을 경우에만, 지정한 국가명으로 변경
def func(row):
    if row['Country_Region'] in json_data:
        row['Country_Region'] = json_data[row['Country_Region']]
    return row
doc = doc.apply(func, axis=1)
doc.head()

참고: 파일명으로 데이터 변환하기

  • lstrip(): 앞에(왼쪽에)서 특정 데이터 삭제하기, rstrip(): 뒤에(오른쪽에)서 특정 데이터 삭제하기
  • replace(변경전데이터, 변경후데이터): 문자열에서 변경전데이터 를 변경후데이터 로 변경
data = "01-22-2020.csv"
date_column = data.split(".")[0].lstrip('0').replace('-', '/')
date_column

'1/22/2020’

data = "01-22-2020.csv"
data.split('.')[0].lstrip("0").replace('-', '/')

'1/22/2020’

doc.columns

Index(['Province_State', 'Country_Region', 'Confirmed'], dtype='object')

doc.head()

 

5. 중복 데이터 합치기

groupby() : 그룹별로 데이터를 집계하는 함수

  • 동일한 컬럼값으로 묶어서 통계 또는 평균등을 확인할 수 있음
df = pd.DataFrame({
    '성별': ['남', '남', '남'],
    '이름': ['David', 'Dave', 'Dave'],
    '수학': [100, 50, 80],
    '국어': [80, 70, 50]    
})
df

df.groupby('이름').mean()

  • 국가별 총 확진자수 구하기
import pandas as pd

doc = pd.read_csv(PATH + "01-22-2020.csv", encoding='utf-8-sig')
try:
    doc = doc[['Province_State', 'Country_Region', 'Confirmed']]  # 1. 특정 컬럼만 선택해서 데이터프레임 만들기
except:
    doc = doc[['Province/State', 'Country/Region', 'Confirmed']]  # 1. 특정 컬럼만 선택해서 데이터프레임 만들기
    doc.columns = ['Province_State', 'Country_Region', 'Confirmed']
doc = doc.dropna(subset=['Confirmed'])     # 2. 특정 컬럼에 없는 데이터 삭제하기
doc = doc.astype({'Confirmed': 'int64'})   # 3. 특정 컬럼의 데이터 타입 변경하기
doc.head()

doc.groupby('Country_Region').sum()  # 4. Country_Region 컬럼값이 동일한 케이스를 그룹화해서, 각 그룹별 합계 확인하기

 

6. 데이터 전처리하기

지금까지의 과정을 모두 한데 모아서, 함수로 만들기

  1. csv 파일 읽기
  2. 'Country_Region', 'Confirmed' 두 개의 컬럼만 가져오기
  3. 'Confirmed' 에 데이터가 없는 행 삭제하기
  4. 'Country_Region'의 국가명을 여러 파일에 일관되게 변경하기
  5. 'Confirmed' 데이터 타입을 int64(정수) 로 변경
  6. 'Country_Region' 를 기준으로 중복된 데이터를 합치기
  7. 파일명을 기반으로 날짜 문자열 변환하고, 'Confirmed' 컬럼명 변경하기
import json

with open('COVID-19-master/csse_covid_19_data/country_convert.json', 'r', encoding='utf-8-sig') as json_file:
    json_data = json.load(json_file)

def country_name_convert(row):
    if row['Country_Region'] in json_data:
        return json_data[row['Country_Region']]
    return row['Country_Region']

def create_dateframe(filename):

    doc = pd.read_csv(PATH + filename, encoding='utf-8-sig')  # 1. csv 파일 읽기
    try:
        doc = doc[['Country_Region', 'Confirmed']]  # 2. 특정 컬럼만 선택해서 데이터프레임 만들기
    except:
        doc = doc[['Country/Region', 'Confirmed']]  # 2. 특정 컬럼만 선택해서 데이터프레임 만들기
        doc.columns = ['Country_Region', 'Confirmed']
    doc = doc.dropna(subset=['Confirmed'])     # 3. 특정 컬럼에 없는 데이터 삭제하기
    doc['Country_Region'] = doc.apply(country_name_convert, axis=1)   # 4. 'Country_Region'의 국가명을 여러 파일에 일관되게 변경하기
    doc = doc.astype({'Confirmed': 'int64'})   # 5. 특정 컬럼의 데이터 타입 변경하기
    doc = doc.groupby('Country_Region').sum()  # 6. 특정 컬럼으로 중복된 데이터를 합치기

    # 7. 파일명을 기반으로 날짜 문자열 변환하고, 'Confirmed' 컬럼명 변경하기
    date_column = filename.split(".")[0].lstrip('0').replace('-', '/') 
    doc.columns = [date_column]
    return doc

테스트해보기

doc1 = create_dateframe("01-22-2020.csv")
doc2 = create_dateframe("04-01-2020.csv")

doc1.head()

doc2.head()

데이터프레임 합치기

doc = pd.merge(doc1, doc2, how='outer', left_index=True, right_index=True)
doc.head()

없는 데이터는 0으로 값 대체하기

doc = doc.fillna(0)
doc

참고: 특정 폴더 파일 리스트 확인하기

  • split() 함수를 사용해서 특정 확장자를 가진 파일 리스트만 추출 가능
  • 문자열변수.split('.') 은 ['파일명', '확장자'] 와 같은 리스트가 반환되므로, 문자열변수.split('.')[-1] 을 통해, 이 중에서 마지막 아이템을 선택하면 됨
import os

PATH = 'COVID-19-master/csse_covid_19_data/csse_covid_19_daily_reports/'
file_list = os.listdir(PATH)
csv_list = list()

for file in file_list:
    if file.split(".")[-1] == 'csv':
        csv_list.append(file)

print (csv_list)

참고: 리스트 정렬

  • 리스트변수.sort() : 오름차순 정렬 (디폴트)
  • 리스트변수.sort(reverse=True) : 내림차순 정렬
csv_list.sort()
csv_list

 

7. 여러 데이터 수집, 전처리해서, 하나의 데이터프레임 만들기

  1. 필요한 파일 리스트만 추출하기
  2. 파일 리스트 정렬하기
  3. 데이터프레임 전처리하기 (별도 create_dateframe() 함수)
  4. 데이터프레임 합치기

최종 코드

import json
import pandas as pd

with open('COVID-19-master/csse_covid_19_data/country_convert.json', 'r', encoding='utf-8-sig') as json_file:
    json_data = json.load(json_file)

def country_name_convert(row):
    if row['Country_Region'] in json_data:
        return json_data[row['Country_Region']]
    return row['Country_Region']

def create_dateframe(filename):

    doc = pd.read_csv(PATH + filename, encoding='utf-8-sig')  # 1. csv 파일 읽기
    try:
        doc = doc[['Country_Region', 'Confirmed']]  # 2. 특정 컬럼만 선택해서 데이터프레임 만들기
    except:
        doc = doc[['Country/Region', 'Confirmed']]  # 2. 특정 컬럼만 선택해서 데이터프레임 만들기
        doc.columns = ['Country_Region', 'Confirmed']
    doc = doc.dropna(subset=['Confirmed'])     # 3. 특정 컬럼에 없는 데이터 삭제하기
    doc['Country_Region'] = doc.apply(country_name_convert, axis=1)   # 4. 'Country_Region'의 국가명을 여러 파일에 일관되게 변경하기
    doc = doc.astype({'Confirmed': 'int64'})   # 5. 특정 컬럼의 데이터 타입 변경하기
    doc = doc.groupby('Country_Region').sum()  # 6. 특정 컬럼으로 중복된 데이터를 합치기

    # 7. 파일명을 기반으로 날짜 문자열 변환하고, 'Confirmed' 컬럼명 변경하기
    date_column = filename.split(".")[0].lstrip('0').replace('-', '/') 
    doc.columns = [date_column]
    return doc
import os

def generate_dateframe_by_path(PATH):

    file_list, csv_list = os.listdir(PATH), list()
    first_doc = True
    for file in file_list:
        if file.split(".")[-1] == 'csv':
            csv_list.append(file)
    csv_list.sort()
    
    for file in csv_list:
        doc = create_dateframe(file)
        if first_doc:
            final_doc, first_doc = doc, False
        else:
            final_doc = pd.merge(final_doc, doc, how='outer', left_index=True, right_index=True)

    final_doc = final_doc.fillna(0)
    return final_doc
PATH = 'COVID-19-master/csse_covid_19_data/csse_covid_19_daily_reports/'
doc = generate_dateframe_by_path(PATH)
doc

참고: 데이터 타입 변환이 가능한 모든 열의 데이터 타입 변경

pd.astype()

  • object 는 파이썬의 str 또는 혼용 데이터 타입 (문자열)
  • int64 는 파이썬의 int (정수)
  • float64 는 파이썬의 float (부동소숫점)
  • bool 는 파이썬의 bool (True 또는 False 값을 가지는 boolean)
doc = doc.astype('int64')
doc

 

pandas 라이브러리로 csv 파일 쓰기

  • pandas dataframe 데이터를 csv 파일로 저장하기 위해, to_csv() 함수 사용
doc.to_csv("00_data/students_default.csv")
  • encoding 옵션 사용 가능
doc.to_csv("COVID-19-master/final_df.csv")
doc.to_csv("00_data/students_default.csv", encoding='utf-8-sig')

 

  • 최종 데이터에 날짜가 2020 1/1 2021 1/1 2022 1/1 이런 식으로 되어 있어서 수정하였다
  • 방법 1
  • doc = doc.reindex(sorted(doc.columns, key=pd.to_datetime), axis=1)

  • 방법 2
def generate_dateframe_by_path(PATH):
    file_list, csv_list = os.listdir(PATH), list()
    first_doc = True
    for file in file_list:
        if file.split(".")[-1] == 'csv':
            csv_list.append(file)
    #데이터 정렬 코드
    ## 방법1
    csv_df = pd.DataFrame(csv_list)
    csv_df
    csv_df['year'] = csv_df[0].str.split('.').str[0].str.split('-').str[-1]
    csv_df['day'] = csv_df[0].str.split('.').str[0].str.split('-').str[-2]
    csv_df['month'] = csv_df[0].str.split('.').str[0].str.split('-').str[-3]
    csv_df = csv_df.sort_values(['year','month','day'])
    csv_list = list(csv_df[0])
    ##방법2
    csv_list = sorted(csv_list,key=lambda x: (x[6:10],x[:2],x[3:5]))
    ##방법3
    csv_list = sorted(csv_list,key=lambda x: pd.to_datetime(x.split('.')[0],format='%m-%d-%Y'))

 

  • 방법3
def generate_dateframe_by_path(PATH):

    file_list, csv_list = os.listdir(PATH), list()
    first_doc = True
    for file in file_list:
        if file.split(".")[-1] == 'csv':
            csv_list.append(file)
    csv_list.sort()
    
    def extract_date(filename):
        date_part = filename.split('.')[0]  # 파일명에서 날짜 부분 추출
        return datetime.strptime(date_part, '%m-%d-%Y')

# 날짜를 추출하고 정렬합니다.
    sorted_dates = sorted(csv_list, key=extract_date)