본문 바로가기

Data_Analysis_Track_33/Python

Python_Pandas_05(DataFrame 합치기)

데이터프레임 합치기 : 두개 이상의 DataFrame을 합쳐 하나의 DataFrame으로 만든다.

  • 수직결합
    • 단순결합으로 여러개의 DataFrame들의 같은 컬럼끼리 수직으로 합친다.
  • 수평결합
    • 연관성 있는 여러 데이터를 하나로 합쳐서 조회하는 JOIN 처리를 한다.
    • JOIN은 합치려는 DataFrame들의 index 나 특정 컬럼의 값이 같은 행 끼리 합친다.

데이터셋 읽기
- stocks_2016.csv, stocks_2017.csv, stocks_2018.csv : 년도별 보유 주식
- stocks_info.csv : 주식 정보

 

 

import pandas as pd

pd.read_csv("data/stocks_2016.csv")
pd.read_csv("data/stocks_2017.csv")
pd.read_csv("data/stocks_2018.csv")
pd.read_csv("data/stocks_info.csv")

위와 같이 하나씩 pd.read_csv로 한다면 코드의 가독성이 떨어질 수 있다.

아래와 같이 여러개의 데이터셋을 한번에 읽어준다.

# 파일명이 다 제각각 다른경우(패턴이 없는 경우)는 리스트에 전체 경로를 다 넣는다.
["data/stocks_2016.csv", "data/stocks_2017.csv", 
 "data/stocks_2018.csv", "data/stocks_info.csv"]

파일들이 stocks_ 뒤에 글자로 시작하기에 다음과 같이 파일들을 읽는다.

files = ["2016", "2017", "2018", "info"]
stock_2016, stock_2017, stock_2018, stock_info = [pd.read_csv(f"data/stocks_{file}.csv") for file in files]
stock_2016.shape, stock_2017.shape, stock_2018.shape, stock_info.shape

파일들을 조회해 본다.

from glob import glob   #  특정 디렉토리안의 파일들의 경로를 조회
## 파일명: * : 0개이상의 모든 글자.
## 디렉토리: ** : 모든 하위 디렉토리.

[pd.read_csv(file) for file in glob("data/stock*.csv")]

 

  • "data/*.csv"  -> data 디렉토리 바로 아래있는 파일들중 확장자가 csv인 파일들의 경로
  • "data/**/*.csv" -> data 디렉토리 + 그 하위 디렉토리에 있는 모든 csv파일.
stock_2018 # 파일 확인

stock_info

concat() 이용
- 수직, 수평 결합 모두 지원한다.
- 하나의 데이터셋을 여러 DataFrame으로 나눈 것을 하나의 DataFrame으로 합칠 때 사용한다.

 

- 수직 결합 (행이 늘어나도록 합친다.)
    - 컬럼명이 같은 열끼리 합친다.
    - 같은 column 명이 없는 열들도 결과 DataFrame에 들어간다.(default)
        - full outer join개념
- 수평결합 (열이 늘어나도록 합친다.)
    - index명이 같은 행 끼리 합친다. (equi-join)
    - 같은 index명이 없는 행들도 결과 DataFrame에 들어간다.(default)
        - full outer join

 

 

pd.concat(objs, [, key=리스트]), axis=0, join='outer' )

 

- 매개변수
    - objs: 합칠 DataFrame들을 리스트로 전달
    - keys=[] 를 이용해 합친 행들을 구분하기 위한 다중 인덱스 처리
    - axis
        - 0 또는 index : 수직결합
        - 1 또는 columns : 수평결합
    - join: 합치는 방식으로 다음 문자열을 값으로 설정한다.
        - 'outer'(기본값): full outer join
        - 'inner': inner join (동일한 index명, column명 끼리 합친다.)

 

조인(join)
- 여러 데이터프레임에 흩어져 있는 정보 중 필요한 정보만 모아서 결합하기 위한 것.
- 두개 이상의 데이터프레임을 특정 컬럼(열)의 값이 같은 행 끼리 수평 결합하는 것.
- Inner Join, Left Outer Join, Right Outer Join, Full Outer Join

 

# default 방향: 0 -> 수직 결합. 같은 컬럼명끼리 합친다.
stocks = pd.concat([stock_2016, stock_2017, stock_2018])
stocks.shape

 

stocks.head()

ignore_index=True -> index 이름을 버리고 index가 0번 ~ n번까지 이름이 붙는다.

stocks2 = pd.concat([stock_2016, stock_2017, stock_2018], 
                    ignore_index=True # index이름은 합칠때 무시.(버린다.)
                   )
stocks2

DataFrame을 구분할 수 있는 index 추가

stocks3 = pd.concat([stock_2016, stock_2017, stock_2018], 
                    keys=["2016년", "2017년", "2018년"] # 각 DataFrame을 구분할 수 있는 index를 추가. => Multi index
                   )
stocks3
  • multi index: 컬럼명이나 index 명이 여러개의 값으로 구성된 것.
  • level : 컬럼을 구성하는 값들의 단위(단계)를 level이라고 함.
  • 밖에서 안으로 들어오는 방향으로 0, 1, 2 level이 됨. (반대방향은 음수 index)
  • level_0 | level_1
  • 2016   |   0
stocks3.loc['2016년']  # 멀티 인덱스 -> level 0 기준 조회
stocks3.loc[('2016년', 0)] # level 0, level 1 묶어서 조회 -> 튜플로 묶어서 전달.

 

# 멀티 index 행/컬럼을 조회하는 메소드
stocks3.xs(0, # 조회할 컬럼/행이름
           axis=0, # 0: 행조회, 1: 열조회
           level=1  # 조회할 이름의 level 위치.
          )

수평조인

### 행기준(수평)으로 합치기 -> index name이 같은 행끼리 합친다.
stocks4 = pd.concat([stock_2016, stock_2017, stock_2018], 
                   axis=1)
stocks4

각 DataFrame 값 확인, # 숫자 -> DataFrame이 가진 index의 값

stock_2016 # 0, 1, 2
stock_2017 # 0, 1, 2, 3, 4, 5
stock_2018 # 0, 1, 2

 

stock5 = pd.concat([stock_2016, stock_2017, stock_2018], 
                  axis=1, # 수평방향으로 합치기.
                  join="inner" # inner join => 같은 index이름끼리만 합친다.
        #           , ignore_index=True, # 수평->컬럼명을 무시
                  , keys=['2016년', '2017년', '2018년']  # 컬럼: ㄴmulti index
                 )
stock5

 

stock5['2016년'] # level 0 기준으로 조회
stock5[['2016년', '2018년']]

 

stock5[('2016년', 'Shares')] # (Level0, Level1) -> tuple로 묶는다.

 

stock5.xs('Shares', level=-1, axis=1)

조인을 통한 DataFrame 합치기
- 연관성있는 둘 이상의 DataFrame을 하나로 합친다.
    - ex) 고객과 주문정보, 교수와 수업정보, 직원과 부서정보
- join()
    - 2개 이상의 DataFrame을 조인할 때 사용
- merge()
    - 2개의 DataFrame의 조인만 지원


join()

dataframe객체.join(others, how='left', lsuffix='', rsuffix='')


- df_A.join(df_b), df_A.join([df_b, df_c, df_d])
- 두개 이상의 DataFrame들을 조인 할 수 있다.
    - 조인 기준: index가 같은 값인 행끼리 합친다. (equi-join)
    - 조인 기본 방식: Left Outer Join
- 매개변수
    - lsuffix, rsuffix
        - 조인 대상 DataFrame에 같은 이름의 컬럼이 있으면 에러 발생.
        - 같은 이름이 있는 경우 붙일 접미어 지정
    - how :조인방식. 'left', 'right', 'outer', 'inner'. left가 기본

 

 

# stock_info: Symbol
# stock_2018: Symbol
stock_info.join(stock_2018, lsuffix='_info')

 

# stock_info: Symbol
# stock_2018: Symbol
## Symbol을 index로 변경
join_result1 = stock_info.set_index("Symbol").join(stock_2018.set_index("Symbol"))
join_result1

inner join

join_result2 = stock_info.set_index("Symbol").join(stock_2018.set_index("Symbol"),
                                                  how="inner")
join_result2

 

3개의 DataFrame join

stock_info.set_index("Symbol").join([stock_2016.set_index("Symbol").add_suffix('_2016'),
                                     stock_2017.set_index("Symbol").add_suffix('_2017')]
                                   )

column명 뒤에 접미어 붙이기

stock_2016.set_index("Symbol").add_suffix("_2016") # 컬럼명 뒤에 접미어를 붙여준다. (add_prefix() : 접두어)

merge()

df_a.merge(df_b)


- 두개의 DataFrame간의 조인만 가능하다.
    - 조인 기준
        - 같은 컬럼명을 기준으로 equi-join을 하는 것이 기본이다.
        - 조인기준을 다양하게 정할 수 있다.
            - 컬럼, index등을 기준으로 같은 행끼리 join 하도록 설정할 수 있다.
- 조인 기본 방식
    - inner join
    - how 매개변수를 이용해 변경이 가능하다.

dataframe.merge(합칠dataframe, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False)


- 매개변수
    - on : 같은 컬럼명이 여러개일때 join 대상 컬럼을 선택
    - right_on, left_on : 조인할 때 사용할 왼쪽,오른쪽 Dataframe의 컬럼명.
    - left_index, right_index: 조인 할때 index를 사용할 경우 True로 지정
    - how : 조인 방식. 'left', 'right', 'outer', 'inner'. 기본: inner
    - suffixes: 두 DataFrame에 같은 이름의 컬럼명이 있을 경우 구분을 위해 붙인 접미어를 리스트로 설정
        - 생략시 x, y를 붙인다.

 

# default: 같은이름의 컬럼명을 기준으로 join
stock_info.merge(stock_2016, 
                how='left' ## default: inner
                )

 

stock2016 = stock_2016.set_index("Symbol")
stock2016

 

# stock_info: Symbol - 컬럼, stock2016: Symbol - index
stock_info.merge(stock2016
                , left_on="Symbol"  # 왼쪽 DF(stock_info)의 join 컬럼을 지정.
                , right_index=True  # 오른쪽 DF(stock2016)의 index를 join 기준으로 사용.
                )

 

# 동일한 이름의 컬럼이 여러개이고 이중 join 기준컬럼은 일부를 사용할 경우.
stock_2016.merge(stock_2018, on="Symbol",
                suffixes=["_2016", "_2018"])
  • 하나의 데이터셋을 어떤 특정행 또튼 특정열을 기준으로 단순해 분리 한 경우를 합치는 경우 concat() 사용
    • 수직 결합일 경우는 concat()을 사용해야 한다.
  • 서로 연관성 있는 다른 데이터셋을 결합해서 보는 경우 join(), merge()를 사용한다. (Join)
    • 두 개 이상의 DataFrame을 조인할 때는 하는 경우 : join() 사용
    • 두개의 DataFrame을 조인할 때는 merge() 를 사용한다. => 컨트롤이 편하다.

TODO 문제

 

# 1 data/customer.csv, data/order.csv, data/qna.csv 를 DataFrame으로 읽으시오.
file_names = ["customer", "order", "qna"]
customer, order, qna = [pd.read_csv(f"data/{name}.csv") for name in file_names]
customer.shape, order.shape, qna.shape

 

# 2 TODO1에서 읽은 세개의 데이터셋의 정보를 확인하세요. 
print(customer.columns)
print(order.columns)
print(qna.columns)

 

# 3 customer DataFrame과 order DataFrame을 고객정보는 모두 나오도록 join 하세요.
result = customer.merge(order, left_on="id", right_on="cust_id", how='left').drop(columns='cust_id')
result

 

# 4 customer DataFrame의 index를 id컬럼으로 변경.
customer.set_index('id', inplace=True)

customer

 

# 5 4에서 만든 customer DataFrame과 qna DataFrame을 inner join 하세요.
##  join()  - index name 기준
customer.join(qna.set_index('cust_id'), how="inner")

merge() 할 경우

## merge()
customer.merge(qna, left_index=True, right_on="cust_id", how="inner")

 

# 6. 세개의 DataFrame을 고객정보는 모두 나오도록 join 하세요.
customer.join([order.set_index('cust_id'), 
               qna.set_index('cust_id')
              ], how='left')