pandas의 DataFrame에 대한 Inner Join, Outer Join, Left Join, Right Join

판다스에서 데이터프레임은 테이블 형식의 데이터셋입니다. DBMS의 Table들 간에도 Join을 맺을 수 있듯이, 마찬가지로 판다스의 데이터프레임들 간에도 Join을 맺을 수 있습니다. 물론 Join을 맺을 공통 필드가 존재한다면 말입니다.

Join에는 모두 4가지 방식이 존재합니다. 즉, 두 데이터셋 간의 중복된 요소만을 Join하는 Inner Join과 두 데이터셋에 대한 모든 데이터를 Join하는 Outter Join, 그리고 왼쪽 데이터셋을 기준으로 하는 Left Join과 오른쪽 데이터셋을 기준으로 하는 Right Join입니다. 보다 명확한 Join의 파악은 아래의 코드 예제를 통해 파악할 수 있습니다.

먼저 Join 하고자 하는 데이터셋으로, 판다스의 데이터프레임을 아래 코드처럼 정의합니다.

import pandas as pd

data_A = {'key': [1,2,3], 'name': ['Jane', 'John', 'Peter']}
dataframe_A = pd.DataFrame(data_A, columns = ['key', 'name'])

data_B = {'key': [2,3,4], 'age': [18, 15, 20]}
dataframe_B = pd.DataFrame(data_B, columns = ['key', 'age'])

print(dataframe_A)
print(dataframe_B)

결과는 아래와 같습니다.

   key   name
0    1   Jane
1    2   John
2    3  Peter
   key  age
0    2   18
1    3   15
2    4   20

두 데이터프레임 간에는 key라는 공통 필드가 존재하는 것을 볼 수 있습니다. 이를 토대로 먼저 Inner Join에 대한 코드입니다.

df_INNER_JOIN = pd.merge(dataframe_A, dataframe_B, left_on='key', right_on='key', how='inner')
print(df_INNER_JOIN)

위의 코드의 결과는 다음과 같습니다.

   key   name  age
0    2   John   18
1    3  Peter   15

다음은 Outer Join에 대한 코드입니다.

df_OUTER_JOIN = pd.merge(dataframe_A, dataframe_B, left_on='key', right_on='key', how='outer')
print(df_OUTER_JOIN)

결과는 다음과 같습니다.

   key   name   age
0    1   Jane   NaN
1    2   John  18.0
2    3  Peter  15.0
3    4    NaN  20.0

다음은 Left Join에 대한 코드입니다.

df_LEFT_JOIN = pd.merge(dataframe_A, dataframe_B, left_on='key', right_on='key', how='left')
print(df_LEFT_JOIN)

결과는 다음과 같습니다.

   key   name   age
0    1   Jane   NaN
1    2   John  18.0
2    3  Peter  15.0

다음은 Right Join에 대한 코드입니다.

df_RIGHT_JOIN = pd.merge(dataframe_A, dataframe_B, left_on='key', right_on='key', how='right')
print(df_RIGHT_JOIN)

다음은 실행 결과입니다.

   key   name  age
0    2   John   18
1    3  Peter   15
2    4    NaN   20

모든 Join은 pd.merge 함수를 통해 이루어지는데요. 위의 예제 코드를 보면 두 데이터프레임의 Join 필드가 모두 ‘key’라는 것을 알 수 있습니다. 이처럼 Join 필드의 이름이 동일할 경우 pd.merge의 left_on과 right_on 인자 대신 on 인자 하나로 대체가 가능합니다. 예를들어, Inner Join의 경우는 아래와 같습니다.

df_INNER_JOIN = pd.merge(dataframe_A, dataframe_B, on='key')

pd.merge 함수의 인자중 how도 생략되었는데, 이는 Inner Join이 pd.merge의 인자 how의 기본값이기 때문입니다.

네이버 주식 서비스로부터 종목 시가, 종가, 고가, 저가, 거래량, 전일대비에 대한 시계열 데이터 얻기

주식 종목에 대한 하루 단위의 시가, 종가, 거래량 등을 웹을 통해 얻을 수 있는데요. 이러한 데이터를 파이썬을 이용해, 네이버의 주식 서비스로부터 얻는 코드에 대해 설명합니다.

코드는 다음과 같습니다. 원하는 종목에 대해 원하는 페이지만큼.. (이 부분은 주식 서비스마다 가능 여부 및 방식이 달라짐) 정보를 얻어옵니다.

import requests
from bs4 import BeautifulSoup

def print_stock_price(code, page_num):
    result = [[], [], [], [], [], [], [], [], []]

    for n in range(page_num):
        url = 'https://finance.naver.com/item/sise_day.nhn?code='+code+'&page='+str(n+1)
        print(url)

        r = requests.get(url)

        if not r.ok: 
            print('Not more data !')
            break

        html = r.content
        soup = BeautifulSoup(html, 'html.parser')
        tr = soup.select('table > tr')

        for i in range(1, len(tr)-1):
            td = tr[i].select('td')
            if td[0].text.strip():
                result[0].append(td[0].text.strip()) # 날짜
                result[1].append(td[1].text.strip()) # 종가
                
                img = td[2].select('img')
                if len(img) != 0: 
                    if 'src' in img[0].attrs:
                        src = img[0]['src']
                        if 'up' in src: result[2].append('상승')
                        else: result[2].append('하락')
                else: result[2].append('보합')

                result[3].append(td[2].text.strip()) # 전일대비
                result[4].append(td[3].text.strip()) # 시장가
                result[5].append(td[4].text.strip()) # 최고가
                result[6].append(td[5].text.strip()) # 최저가
                result[7].append(td[6].text.strip()) # 거래량

    for i in range(len(result[0])):
        #     날짜          종가           상승/하락/보합+a           시장가         최고가        최저가        거래량
        print(result[0][i], result[1][i], result[2][i]+result[3][i], result[4][i], result[5][i], result[6][i], result[7][i])

print_stock_price(code='005930', page_num=1)

코드를 보면, print_stock_price 함수의 url 변수에 저장된 주소에 대한 결과 DOM을 해석하고 있는 것을 알 수 있습니다. 즉, DOM에 대한 구조를 먼저 파악해야 한다는 것이 핵심인데요. 위의 코드가 정상적으로 작동할 당시의 실제 DOM의 한가지 예는 다음과 같습니다.

코드와 추출하고자 하는 DOM 요소가 명확하게 1:1로 매칭되고 있는 것을 확인할 수 있습니다.