상세 컨텐츠

본문 제목

판다스, 데이터 연결하기

판다스 입문

by ZISEN 2021. 3. 27. 15:15

본문

반응형

05 - 1 분석하기 좋은 데이터

깔금한 데이터의 조건

  • 데이터 분석 목적에 맞는 데이터를 모아 새로운 표(Table)를 만들어야 합니다.
  • 측정한 값은 행(row)을 구성해야 합니다.
  • 변수는 열(column)로 구성해야 합니다.

깔끔한 데이터는 데이터 연결부터

예를 들어 주식 데이터를 분석하는 과정에서 '기업 정보'가 있는 데이터 집합과 '주식 가격'이 있는 데이터 집합이 있을 때 '첨단 산업 기업의 주식 가격에 대한 데이터'를 보려면 어떻게 해야 할까? 일단 '기업 정보'에서 첨단 기술을 가진 기업을 찾아야 한다. 그리고 이 기업들의 '주식 가격'을 찾는다. 그런 다음 찾아낸 2개의 데이터를 연결하면 됩니다. 이렇게 데이터 집합은 연관성이 깊은 값끼리 모여 있기 때문에 데이터 연결을 통해 필요한 데이터를 만드는 과정이 반드시 필요합니다.

05 - 2 데이터 연결 기초

1. concat 메서드로 데이터 연결하기

데이터를 연결하려면 concat 메서드를 사용하면 됩니다. concat 메서드의 사용법을 익혀보겠습니다. 준비된 CSV 파일을 읽어 들여 변수 df1, 2, 3에 저장합니다

import pandas as pd

df1 = pd.read_csv('C:/Users/김지상/Downloads/doit_pandas-master/doit_pandas-master/data/concat_1.csv')
df2 = pd.read_csv('C:/Users/김지상/Downloads/doit_pandas-master/doit_pandas-master/data/concat_2.csv')
df3 = pd.read_csv('C:/Users/김지상/Downloads/doit_pandas-master/doit_pandas-master/data/concat_3.csv')

2.concat 메서드에 연결하려는 데이터프레임을 리스트에 담아 전달하면 연결한 데이터프레임을 반환합니다. concat 메서드는 데이터프레임을 연결할 때 위에서 아래 방향으로 연결합니다. 그리고 df1, 2, 3은 열의 이름이 모두 A, B, C, D로 같습니다. 그래서 데이터프레임을 연결한 다음에도 열이 그대로 유지됩니다.

row_concat = pd.concat([df1, df2, df3])
print(row_concat)

     A    B    C    D
0   a0   b0   c0   d0
1   a1   b1   c1   d1
2   a2   b2   c2   d2
3   a3   b3   c3   d3
0   a4   b4   c4   d4
1   a5   b5   c5   d5
2   a6   b6   c6   d6
3   a7   b7   c7   d7
0   a8   b8   c8   d8
1   a9   b9   c9   d9
2  a10  b10  c10  d10
3  a11  b11  c11  d11

3.연결한 데이터프레임에서 행 데이터를 추출해 봅시다. concat 메서드는 전달받은 리스트의 요소 순서대로 데이터를 연결합니다. 그래서 기존 데이터프레임에 있던 인덱스도 그대로 유지됩니다. 다음은 데이터프레임에서 네 번째 행을 추출한 것입니다.

 

print(row_concat.iloc[3, ])

A    a3
B    b3
C    c3
D    d3
Name: 3, dtype: object

4.데이터프레임에 시리즈 연결하기

이번에는 데이터프레임에 시리즈를 추가해 보겠습니다. 먼저 리스트를 시리즈로 변환합니다.

new_row_series = pd.Series(['n1', 'n2', 'n3', 'n4'])

5.concat 메서드로 데이터프레임과 시리즈를 연결해 봅시다. 시리즈가 새로운 행으로 추가될 것 같죠? 하지만 행이 아니라 새로운 열로 추가됩니다. 그래서 NaN이라는 값도 많이 생겼습니다. 앞으로 NaN을 누락값이라고 부르겠습니다.

print(pd.concat([df1, new_row_series]))

     A    B    C    D    0
0   a0   b0   c0   d0  NaN
1   a1   b1   c1   d1  NaN
2   a2   b2   c2   d2  NaN
3   a3   b3   c3   d3  NaN
0  NaN  NaN  NaN  NaN   n1
1  NaN  NaN  NaN  NaN   n2
2  NaN  NaN  NaN  NaN   n3
3  NaN  NaN  NaN  NaN   n4

 

행이 1개라도 반드시 데이터프레임에 담아 연결해야 합니다

시리즈를 데이터프레임의 새로운 행으로 연결하려고 하면 제대로 되지 않습니다. 시리즈에는 열 이름이 없기 때문입니다. 그래서 시리즈를 새로운 열로 간주하여 0이라는 이름의 열로 추가한 것이죠.

행 1개로 구성된 데이터프레임 생성하여 연결하기

1.시리즈는 행이 1개인 데이터프레임이라고 생각해도 됩니다. 다음은 1개의 행을 가지는 데이터프레임을 생성하여 df1에 연결한 것입니다.

new_row_df = pd.DataFrame([['n1', 'n2', 'n3', 'n4']], columns=['A', 'B', 'C', 'D'])
print(new_row_df)

    A   B   C   D
0  n1  n2  n3  n4

print(pd.concat([df1, new_row_df]))

    A   B   C   D
0  a0  b0  c0  d0
1  a1  b1  c1  d1
2  a2  b2  c2  d2
3  a3  b3  c3  d3
0  n1  n2  n3  n4

2.concat 메서드는 한 번에 2개 이상의 데이터프레임을 연결할 수 있는 메서드입니다. 만약 연결할 데이터프레임이 1개라면 append 메서드를 사용해도 됩니다.

print(df1.append(new_row_df))

    A   B   C   D
0  a0  b0  c0  d0
1  a1  b1  c1  d1
2  a2  b2  c2  d2
3  a3  b3  c3  d3
0  n1  n2  n3  n4

3.append 메서드와 딕셔너리를 사용하면 더욱 간편하게 행을 연결할 수 있습니다. 이때 ignore_index를 True로 설정하면 데이터를 연결한 다음 데이터프레임의 인덱스를 0부터 다시 지정합니다.

data_dict = {'A': 'n1', 'B': 'n2', 'C': 'n3', 'D': 'n4'}
print(df1.append(data_dict, ignore_index=True))

    A   B   C   D
0  a0  b0  c0  d0
1  a1  b1  c1  d1
2  a2  b2  c2  d2
3  a3  b3  c3  d3
4  n1  n2  n3  n4

다양한 방법으로 데이터 연결하기

1. ignore_index 인자 사용하기

ignore_index를 True로 지정하면 데이터를 연결한 다음 데이터프레임의 인덱스를 0부터 다시 지정합니다.

row_concat_i = pd.concat([df1, df2, df3], ignore_index=True)
print(row_concat_i)

      A    B    C    D
0    a0   b0   c0   d0
1    a1   b1   c1   d1
2    a2   b2   c2   d2
3    a3   b3   c3   d3
4    a4   b4   c4   d4
5    a5   b5   c5   d5
6    a6   b6   c6   d6
7    a7   b7   c7   d7
8    a8   b8   c8   d8
9    a9   b9   c9   d9
10  a10  b10  c10  d10
11  a11  b11  c11  d11

2. 열 방향으로 데이터 연결하기

만약 행 방향이 아니라 열 방향으로 데이터를 연결하려면 어떻게 해야 할까? concat 메서드의 axis 인자를 1로 지정하면 됩니다. 다음은 df1, df2, df3을 열 방향으로 연결한 것입니다.

col_concat = pd.concat([df1, df2, df3], axis=1)
print(col_concat)

    A   B   C   D   A   B   C   D    A    B    C    D
0  a0  b0  c0  d0  a4  b4  c4  d4   a8   b8   c8   d8
1  a1  b1  c1  d1  a5  b5  c5  d5   a9   b9   c9   d9
2  a2  b2  c2  d2  a6  b6  c6  d6  a10  b10  c10  d10
3  a3  b3  c3  d3  a7  b7  c7  d7  a11  b11  c11  d11

3.만약 같은 열 이름이 있는 데이터프레임에서 열 이름으로 데이터를 추출하면 해당 열 이름의 데이터를 모두 추출합니다.

print(col_concat['A'])

    A   A    A
0  a0  a4   a8
1  a1  a5   a9
2  a2  a6  a10
3  a3  a7  a11

4.다음과 같이 입력하면 간편하게 새로운 열을 추가할 수도 있습니다.

col_concat['new_col_list'] = ['n1', 'n2', 'n3', 'n4']
print(col_concat)

    A   B   C   D   A   B   C   D    A    B    C    D new_col_list
0  a0  b0  c0  d0  a4  b4  c4  d4   a8   b8   c8   d8           n1
1  a1  b1  c1  d1  a5  b5  c5  d5   a9   b9   c9   d9           n2
2  a2  b2  c2  d2  a6  b6  c6  d6  a10  b10  c10  d10           n3
3  a3  b3  c3  d3  a7  b7  c7  d7  a11  b11  c11  d11           n4

5.과정 2에서는 데이터프레임의 열 이름을 유지한 채 연결했기 때문에 열 이름이 중복되었습니다. 다음은 ignore_index를 True로 지정하여 열 이름을 다시 지정한 것입니다.

print(pd.concat([df1, df2, df3], axis=1, ignore_index=True))

   0   1   2   3   4   5   6   7    8    9    10   11
0  a0  b0  c0  d0  a4  b4  c4  d4   a8   b8   c8   d8
1  a1  b1  c1  d1  a5  b5  c5  d5   a9   b9   c9   d9
2  a2  b2  c2  d2  a6  b6  c6  d6  a10  b10  c10  d10
3  a3  b3  c3  d3  a7  b7  c7  d7  a11  b11  c11  d11

6. 공통 열과 공통 인덱스만 연결하기

만약 열 이름의 일부가 서로 다른 데이터프레임을 연결하면 어떻게 될까? 앞에서 사용한 df1, df2, df3의 열 이름을 다시 지정하겠습니다.

df1.columns = ['A', 'B', 'C', 'D']
df2.columns = ['E', 'F', 'G', 'H']
df3.columns = ['A', 'C', 'F', 'H']
print(df1)
print(type(df1))

    A   B   C   D
0  a0  b0  c0  d0
1  a1  b1  c1  d1
2  a2  b2  c2  d2
3  a3  b3  c3  d3
<class 'pandas.core.frame.DataFrame'>

print(df2)
print(type(df2))

    E   F   G   H
0  a4  b4  c4  d4
1  a5  b5  c5  d5
2  a6  b6  c6  d6
3  a7  b7  c7  d7
<class 'pandas.core.frame.DataFrame'>

print(df3)
print(type(df3))

     A    C    F    H
0   a8   b8   c8   d8
1   a9   b9   c9   d9
2  a10  b10  c10  d10
3  a11  b11  c11  d11
<class 'pandas.core.frame.DataFrame'>

7.새롭게 열 이름을 부여한 데이터프레임 3개를 concat 메서드로 연결해 보겠습니다. 열 이름이 정렬되며 연결되었습니다. 그리고 데이터프레임에 없는 열 이름의 데이터는 누락값으로 처리되었습니다. 누락값 없이 데이터를 연결하는 방법은 없을까요?

row_concat = pd.concat([df1, df2, df3])
print(row_concat)

     A    B    C    D    E    F    G    H
0   a0   b0   c0   d0  NaN  NaN  NaN  NaN
1   a1   b1   c1   d1  NaN  NaN  NaN  NaN
2   a2   b2   c2   d2  NaN  NaN  NaN  NaN
3   a3   b3   c3   d3  NaN  NaN  NaN  NaN
0  NaN  NaN  NaN  NaN   a4   b4   c4   d4
1  NaN  NaN  NaN  NaN   a5   b5   c5   d5
2  NaN  NaN  NaN  NaN   a6   b6   c6   d6
3  NaN  NaN  NaN  NaN   a7   b7   c7   d7
0   a8  NaN   b8  NaN  NaN   c8  NaN   d8
1   a9  NaN   b9  NaN  NaN   c9  NaN   d9
2  a10  NaN  b10  NaN  NaN  c10  NaN  d10
3  a11  NaN  b11  NaN  NaN  c11  NaN  d11

8.데이터프레임의 공통 열만 골라 연결하면 누락값이 생기지 않을 것입니다. 공통 열만 골라서 연결하려면 join 인자를 inner로 지정해야 합니다. 아쉽게도 df1, df2, df3은 공통 열이 없습니다. 따라서 세 데이터프레임의 공통 열을 연결한 결괏값으로 Empty DataFrame이 출력됩니다.

print(pd.concat([df1, df2, df3], join='inner'))

Empty DataFrame
Columns: []
Index: [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]

9.df1, df3의 공통 열만 골라서 연결해보자. 그러면 공통 열인 A와 C만 연결됩니다.

print(pd.concat([df1, df3], ignore_index=False, join='inner'))

     A    C
0   a0   c0
1   a1   c1
2   a2   c2
3   a3   c3
0   a8   b8
1   a9   b9
2  a10  b10
3  a11  b11

10.이번에는 데이터프레임을 행 방향으로 연결해 보자. df1, df2, df3의 인덱스를 다시 지정해 보겠습니다.

df1.index = [0, 1, 2, 3]
df2.index = [4, 5, 6, 7]
df3.index = [0, 2, 5, 7]

print(df1)

    A   B   C   D
0  a0  b0  c0  d0
1  a1  b1  c1  d1
2  a2  b2  c2  d2
3  a3  b3  c3  d3

print(df2)

    E   F   G   H
4  a4  b4  c4  d4
5  a5  b5  c5  d5
6  a6  b6  c6  d6
7  a7  b7  c7  d7

print(df3)

     A    C    F    H
0   a8   b8   c8   d8
2   a9   b9   c9   d9
5  a10  b10  c10  d10
7  a11  b11  c11  d11

11.concat 메서드로 df1, df2, df3을 행방향으로 연결하면 과정 2와 비슷한 결과가 출력됩니다.

col_concat = pd.concat([df1, df2, df3], axis=1)
print(col_concat)

     A    B    C    D    E    F    G    H    A    C    F    H
0   a0   b0   c0   d0  NaN  NaN  NaN  NaN   a8   b8   c8   d8
1   a1   b1   c1   d1  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN
2   a2   b2   c2   d2  NaN  NaN  NaN  NaN   a9   b9   c9   d9
3   a3   b3   c3   d3  NaN  NaN  NaN  NaN  NaN  NaN  NaN  NaN
4  NaN  NaN  NaN  NaN   a4   b4   c4   d4  NaN  NaN  NaN  NaN
5  NaN  NaN  NaN  NaN   a5   b5   c5   d5  a10  b10  c10  d10
6  NaN  NaN  NaN  NaN   a6   b6   c6   d6  NaN  NaN  NaN  NaN
7  NaN  NaN  NaN  NaN   a7   b7   c7   d7  a11  b11  c11  d11

12.과정 9와 비슷한 방법으로 df1, df3의 공통 행만 골라 연결해 보자. 그러면 공통 행인 0과 2만 출력됩니다.

print(pd.concat([df1, df3], axis=1, join='inner'))

    A   B   C   D   A   C   F   H
0  a0  b0  c0  d0  a8  b8  c8  d8
2  a2  b2  c2  d2  a9  b9  c9  d9

 

 

05 - 3 데이터 연결 마무리

merge 메서드 사용하기

1.다음은 특정 위치의 날씨 정보에 필요한 데이터 집합을 모두 불러온 것입니다. person은 관측한 사람의 이름, site는 관측 위치, visited는 관측 날짜, survey는 날씨 정보입니다.

person = pd.read_csv('C:/Users/김지상/Downloads/doit_pandas-master/doit_pandas-master/data/survey_person.csv')
site = pd.read_csv('C:/Users/김지상/Downloads/doit_pandas-master/doit_pandas-master/data/survey_site.csv')
survey = pd.read_csv('C:/Users/김지상/Downloads/doit_pandas-master/doit_pandas-master/data/survey_survey.csv')
visited = pd.read_csv('C:/Users/김지상/Downloads/doit_pandas-master/doit_pandas-master/data/survey_visited.csv')
print(person)

      ident   personal    family
0      dyer    William      Dyer
1        pb      Frank   Pabodie
2      lake   Anderson      Lake
3       roe  Valentina   Roerich
4  danforth      Frank  Danforth

print(site)

    name    lat    long
0   DR-1 -49.85 -128.57
1   DR-3 -47.15 -126.72
2  MSK-4 -48.87 -123.40

print(visited)

   ident   site       dated
0    619   DR-1  1927-02-08
1    622   DR-1  1927-02-10
2    734   DR-3  1939-01-07
3    735   DR-3  1930-01-12
4    751   DR-3  1930-02-26
5    752   DR-3         NaN
6    837  MSK-4  1932-01-14
7    844   DR-1  1932-03-22

print(survey)

    taken person quant  reading
0     619   dyer   rad     9.82
1     619   dyer   sal     0.13
2     622   dyer   rad     7.80
3     622   dyer   sal     0.09
4     734     pb   rad     8.41
5     734   lake   sal     0.05
6     734     pb  temp   -21.50
7     735     pb   rad     7.22
8     735    NaN   sal     0.06
9     735    NaN  temp   -26.00
10    751     pb   rad     4.35
11    751     pb  temp   -18.50
12    751   lake   sal     0.10
13    752   lake   rad     2.19
14    752   lake   sal     0.09
15    752   lake  temp   -16.00
16    752    roe   sal    41.60
17    837   lake   rad     1.46
18    837   lake   sal     0.21
19    837    roe   sal    22.50
20    844    roe   rad    11.25

2.visited 데이터프레임의 일부 데이터만 떼어 실습에 사용하겠습니다.

visited_subset = visited.loc[[0, 2, 6], ]

3.merge 메서드는 기본적으로 내부 조인을 실행하며 메서드를 사용한 데이터프레임(site)을 왼쪽으로 지정하고 첫 번째 인잣값으로 지정한 데이터프레임(visited_subset)을 오른쪽으로 지정합니다. left_on, right_on 인자는 값이 일치해야 할 왼쪽과 오른쪽 데이터프레임의 열을 지정합니다. 즉, 왼쪽 데이터프레임(site)의 열(name)과 오른쪽 데이터프레임(visited)의 열(site)의 값이 일치하면 왼쪽 데이터프레임을 기준으로 연결합니다.

o2o_merge = site.merge(visited_subset, left_on='name', right_on='site')

print(o2o_merge)


    name    lat    long  ident   site       dated
0   DR-1 -49.85 -128.57    619   DR-1  1927-02-08
1   DR-3 -47.15 -126.72    734   DR-3  1939-01-07
2  MSK-4 -48.87 -123.40    837  MSK-4  1932-01-14

4.다음은 site, visited 데이터프레임을 이용하여 데이터를 연결한 것입니다.

m2o_merge = site.merge(visited, left_on='name', right_on='site')

print(m2o_merge)

   name    lat    long  ident   site       dated
0   DR-1 -49.85 -128.57    619   DR-1  1927-02-08
1   DR-1 -49.85 -128.57    622   DR-1  1927-02-10
2   DR-1 -49.85 -128.57    844   DR-1  1932-03-22
3   DR-3 -47.15 -126.72    734   DR-3  1939-01-07
4   DR-3 -47.15 -126.72    735   DR-3  1930-01-12
5   DR-3 -47.15 -126.72    751   DR-3  1930-02-26
6   DR-3 -47.15 -126.72    752   DR-3         NaN
7  MSK-4 -48.87 -123.40    837  MSK-4  1932-01-14

5.다른 데이터프레임도 연결해 보자. 다음은 person, survey 데이터프레임과 visited, survey 데이터프레임을 merge 메서드로 연결한 것입니다.

ps = person.merge(survey, left_on='ident', right_on='person')
vs = visited.merge(survey, left_on='ident', right_on='taken')

print(ps)
   ident   personal   family  taken person quant  reading
0   dyer    William     Dyer    619   dyer   rad     9.82
1   dyer    William     Dyer    619   dyer   sal     0.13
2   dyer    William     Dyer    622   dyer   rad     7.80
3   dyer    William     Dyer    622   dyer   sal     0.09
4     pb      Frank  Pabodie    734     pb   rad     8.41
5     pb      Frank  Pabodie    734     pb  temp   -21.50
6     pb      Frank  Pabodie    735     pb   rad     7.22
7     pb      Frank  Pabodie    751     pb   rad     4.35
8     pb      Frank  Pabodie    751     pb  temp   -18.50
9   lake   Anderson     Lake    734   lake   sal     0.05
10  lake   Anderson     Lake    751   lake   sal     0.10
11  lake   Anderson     Lake    752   lake   rad     2.19
12  lake   Anderson     Lake    752   lake   sal     0.09
13  lake   Anderson     Lake    752   lake  temp   -16.00
14  lake   Anderson     Lake    837   lake   rad     1.46
15  lake   Anderson     Lake    837   lake   sal     0.21
16   roe  Valentina  Roerich    752    roe   sal    41.60
17   roe  Valentina  Roerich    837    roe   sal    22.50
18   roe  Valentina  Roerich    844    roe   rad    11.25

print(vs)
    ident   site       dated  taken person quant  reading
0     619   DR-1  1927-02-08    619   dyer   rad     9.82
1     619   DR-1  1927-02-08    619   dyer   sal     0.13
2     622   DR-1  1927-02-10    622   dyer   rad     7.80
3     622   DR-1  1927-02-10    622   dyer   sal     0.09
4     734   DR-3  1939-01-07    734     pb   rad     8.41
5     734   DR-3  1939-01-07    734   lake   sal     0.05
6     734   DR-3  1939-01-07    734     pb  temp   -21.50
7     735   DR-3  1930-01-12    735     pb   rad     7.22
8     735   DR-3  1930-01-12    735    NaN   sal     0.06
9     735   DR-3  1930-01-12    735    NaN  temp   -26.00
10    751   DR-3  1930-02-26    751     pb   rad     4.35
11    751   DR-3  1930-02-26    751     pb  temp   -18.50
12    751   DR-3  1930-02-26    751   lake   sal     0.10
13    752   DR-3         NaN    752   lake   rad     2.19
14    752   DR-3         NaN    752   lake   sal     0.09
15    752   DR-3         NaN    752   lake  temp   -16.00
16    752   DR-3         NaN    752    roe   sal    41.60
17    837  MSK-4  1932-01-14    837   lake   rad     1.46
18    837  MSK-4  1932-01-14    837   lake   sal     0.21
19    837  MSK-4  1932-01-14    837    roe   sal    22.50
20    844   DR-1  1932-03-22    844    roe   rad    11.25

6.left_on, right_on에 전달하는 값은 여러 개라도 상관이 없습니다. 다음과 같이 여러 개의 열 이름을 리스트에 담아 전달해도 됩니다. 다음은 ps 데이터프레임의 ident, taken, quant, reading 열의 값과 vs 데이터프레임의 person, ident, quant, reading 열의 값을 이용하여 ps와 vs 데이터프레임을 서로 연결한 것입니다.

ps_vs = ps.merge(vs, left_on=['ident', 'taken', 'quant', 'reading'], right_on=['person', 'ident', 'quant', 'reading'])

7.과정 6에서 연결한 ps_vs 데이터프레임의 첫 번째 행을 살펴보면 양쪽 데이터프레임에 있었던 중복된 열 이름(ident, taken, person)에 접미사 _x, _y가 추가되어 있는 것을 알 수 있습니다. _x는 왼쪽 데이터프레임의 열을 의미하고 _y는 오른쪽 데이터프레임의 열을 의미합니다.

print(ps_vs.loc[0, ])

ident_x           dyer
personal       William
family            Dyer
taken_x            619
person_x          dyer
quant              rad
reading           9.82
ident_y            619
site              DR-1
dated       1927-02-08
taken_y            619
person_y          dyer
Name: 0, dtype: object

 

 

마무리하며

데이터를 연결하는 다양한 방법을 알아보았습니다. 특히 누락값과 중복값을 해결하기 위한 여러 가지 방법에 대해 알아보았습니다. 누락값과 중복값은 데이터 분석을 방해하는 요소가 될 수 있기 때문이죠. 05장을 시작하며 소개한 깔금한 데이터의 조건 중 하나인 '데이터 분석 목적에 맞는 데이터를 모아 새로운 표(Table)를 만들어야 합니다'는 바로 누락값이나 중복값이 없는 상태로 데이터가 잘 연결되어 있어야 한다는 말입니다.

 

출처 : doit 데이터 분석을 위한 판다스 입문

반응형

관련글 더보기