데이터 결합: 병합(Merge)과 조인(Join)

Pandas가 제공하는 중요한 기능 중 하나는 고성능 메모리 내 조인 및 병합 기능으로, 데이터베이스 작업을 해 본 적이 있다면 익숙할 것입니다. 이에 대한 주요 인터페이스는 pd.merge 함수이며 실제로 어떻게 작동하는지 예제를 통해 살펴보겠습니다.

편의상 일반적인 import 이후 이전 장의 display 함수를 다시 정의하겠습니다.

import pandas as pd


class display(object):
    """Display HTML representation of multiple objects"""

    template = """<div style="float: left; padding: 10px;">
    <p style='font-family:"Courier New", Courier, monospace'>{0}</p>{1}
    </div>"""

    def __init__(self, *args):
        self.args = args

    def _repr_html_(self):
        return "\n".join(
            self.template.format(a, eval(a)._repr_html_()) for a in self.args
        )

    def __repr__(self):
        return "\n\n".join(a + "\n" + repr(eval(a)) for a in self.args)

관계 대수(Relational Algebra)

’pd.merge’에 구현된 동작은 관계 대수(Relational Algebra)의 일부입니다. 이는 대부분의 데이터베이스에서 사용할 수 있는 작업의 개념적 기초를 형성하는 관계형 데이터를 조작하기 위한 공식 규칙 세트입니다. 관계 대수 방식의 강점은, 복잡한 데이터 작업을 구성하는 몇 가지 핵심적인 기본 연산을 제공한다는 점에 있습니다. 데이터베이스나 기타 프로그램에서 효율적으로 구현된 기본 작업 어휘를 사용하면 상당히 복잡한 복합 작업을 광범위하게 수행합니다.

Pandas는 pd.merge 함수와 SeriesDataFrame 개체의 관련 join 메서드에서 이러한 기본 구성 요소 중 몇 가지를 구현합니다. 보시다시피 이를 통해 다양한 소스의 데이터를 효율적으로 연결합니다.

조인의 유형

pd.merge 함수는 일대일, 다대일, 다대다 등 다양한 유형의 조인을 구현합니다. 세 가지 유형의 조인 모두 pd.merge 인터페이스에 대한 동일한 호출을 통해 액세스됩니다. 수행되는 조인 유형은 입력 데이터의 형식에 따라 다릅니다. 세 가지 유형의 병합에 대한 몇 가지 간단한 예부터 시작하고 나중에 자세한 옵션에 대해 논의하겠습니다.

일대일 조인

가장 간단한 병합 방식은 일대일(One-to-one) 조인입니다. 이는 데이터 세트 결합: 연결 및 추가에서 본 열별 연결과 여러 면에서 유사합니다. 구체적인 예로, 회사 직원 정보가 담긴 다음 두 DataFrame 객체를 살펴보겠습니다.

df1 = pd.DataFrame(
    {
        "employee": ["Bob", "Jake", "Lisa", "Sue"],
        "group": ["Accounting", "Engineering", "Engineering", "HR"],
    }
)
df2 = pd.DataFrame(
    {"employee": ["Lisa", "Bob", "Jake", "Sue"], "hire_date": [2004, 2008, 2012, 2014]}
)
display("df1", "df2")

df1

employee group
0 Bob Accounting
1 Jake Engineering
2 Lisa Engineering
3 Sue HR

df2

employee hire_date
0 Lisa 2004
1 Bob 2008
2 Jake 2012
3 Sue 2014

이 정보를 단일 DataFrame으로 결합하려면 pd.merge 함수를 사용합니다.

df3 = pd.merge(df1, df2)
df3
employee group hire_date
0 Bob Accounting 2008
1 Jake Engineering 2012
2 Lisa Engineering 2004
3 Sue HR 2014

pd.merge 함수는 각 DataFrameemployee 열이 있음을 인식하고 이 열을 키로 사용하여 자동으로 조인합니다. 병합의 결과는 두 입력의 정보를 결합하는 새로운 ‘DataFrame’입니다. 각 열의 항목 순서가 반드시 유지되는 것은 아닙니다. 이 경우 employee 열의 순서는 df1df2에서 다르며 pd.merge 함수는 이를 올바르게 설명합니다. 또한 인덱스를 기준으로 병합하는 특수한 경우를 제외하면, 병합 과정에서 기존 인덱스가 삭제된다는 점에 유의하세요.(잠시 설명된 ’left_index’ 및 ‘right_index’ 키워드 참조).

다대일 조인

다대일 조인은 두 개의 키 열 중 하나에 중복 항목이 포함된 조인입니다. 다대일 사례의 경우 결과 DataFrame은 중복 항목을 적절하게 유지합니다. 다대일 조인의 다음 예를 살펴보세요.

df4 = pd.DataFrame(
    {
        "group": ["Accounting", "Engineering", "HR"],
        "supervisor": ["Carly", "Guido", "Steve"],
    }
)
display("df3", "df4", "pd.merge(df3, df4)")

df3

employee group hire_date
0 Bob Accounting 2008
1 Jake Engineering 2012
2 Lisa Engineering 2004
3 Sue HR 2014

df4

group supervisor
0 Accounting Carly
1 Engineering Guido
2 HR Steve

pd.merge(df3, df4)

employee group hire_date supervisor
0 Bob Accounting 2008 Carly
1 Jake Engineering 2012 Guido
2 Lisa Engineering 2004 Guido
3 Sue HR 2014 Steve

결과 DataFrame에는 ‘감독자’ 정보가 포함된 추가 열이 있으며, 여기서 정보는 입력에서 요구하는 대로 하나 이상의 위치에서 반복됩니다.

다대다 조인

다대다 조인은 개념적으로 다소 혼란스러울 수 있지만 그럼에도 불구하고 잘 정의되어 있습니다. 왼쪽 및 오른쪽 배열의 키 열에 중복 항목이 포함된 경우 결과는 다대다 병합입니다. 이는 아마도 구체적인 예를 통해 가장 명확해질 것입니다. 특정 그룹과 관련된 하나 이상의 기술을 보여주는 DataFrame이 있는 다음을 고려해보세요. 다대다 조인을 수행하면 개인과 관련된 기술을 복구합니다.

df5 = pd.DataFrame(
    {
        "group": ["Accounting", "Accounting", "Engineering", "Engineering", "HR", "HR"],
        "skills": [
            "math",
            "spreadsheets",
            "software",
            "math",
            "spreadsheets",
            "organization",
        ],
    }
)
display("df1", "df5", "pd.merge(df1, df5)")

df1

employee group
0 Bob Accounting
1 Jake Engineering
2 Lisa Engineering
3 Sue HR

df5

group skills
0 Accounting math
1 Accounting spreadsheets
2 Engineering software
3 Engineering math
4 HR spreadsheets
5 HR organization

pd.merge(df1, df5)

employee group skills
0 Bob Accounting math
1 Bob Accounting spreadsheets
2 Jake Engineering software
3 Jake Engineering math
4 Lisa Engineering software
5 Lisa Engineering math
6 Sue HR spreadsheets
7 Sue HR organization

이 세 가지 유형의 조인을 다른 Pandas 도구와 함께 사용하여 다양한 기능을 구현합니다. 그러나 실제로 데이터 세트는 여기서 작업하는 것만큼 깨끗하지 않습니다. 다음 섹션에서는 조인 작업의 작동 방식을 조정할 수 있도록 pd.merge에서 제공하는 일부 옵션을 고려할 것입니다.

병합 키 사양

우리는 이미 pd.merge의 기본 동작을 살펴보았습니다. 두 입력 사이에서 일치하는 하나 이상의 열 이름을 찾고 이를 키로 사용합니다. 그러나 열 이름이 제대로 일치하지 않는 경우가 많으며 pd.merge는 이를 처리하기 위한 다양한 옵션을 제공합니다.

on 키워드

가장 간단하게는 열 이름이나 열 이름 목록을 사용하는 ‘on’ 키워드를 사용하여 키 열의 이름을 명시적으로 지정합니다.

display("df1", "df2", "pd.merge(df1, df2, on='employee')")

df1

employee group
0 Bob Accounting
1 Jake Engineering
2 Lisa Engineering
3 Sue HR

df2

employee hire_date
0 Lisa 2004
1 Bob 2008
2 Jake 2012
3 Sue 2014

pd.merge(df1, df2, on='employee')

employee group hire_date
0 Bob Accounting 2008
1 Jake Engineering 2012
2 Lisa Engineering 2004
3 Sue HR 2014

이 옵션은 왼쪽과 오른쪽 DataFrame 모두에 지정된 열 이름이 있는 경우에만 작동합니다.

left_on 및 right_on 키워드

때로는 열 이름이 다른 두 개의 데이터 세트를 병합하고 싶을 수도 있습니다. 예를 들어 직원 이름이 “직원”이 아닌 “이름”으로 레이블이 지정된 데이터 세트가 있습니다. 이 경우 left_onright_on 키워드를 사용하여 두 열 이름을 지정합니다.

df3 = pd.DataFrame(
    {"name": ["Bob", "Jake", "Lisa", "Sue"], "salary": [70000, 80000, 120000, 90000]}
)
display("df1", "df3", 'pd.merge(df1, df3, left_on="employee", right_on="name")')

df1

employee group
0 Bob Accounting
1 Jake Engineering
2 Lisa Engineering
3 Sue HR

df3

name salary
0 Bob 70000
1 Jake 80000
2 Lisa 120000
3 Sue 90000

pd.merge(df1, df3, left_on="employee", right_on="name")

employee group name salary
0 Bob Accounting Bob 70000
1 Jake Engineering Jake 80000
2 Lisa Engineering Lisa 120000
3 Sue HR Sue 90000

결과에는 원하는 경우 삭제할 수 있는 중복 열이 있습니다(예: DataFrame.drop() 메서드 사용).

pd.merge(df1, df3, left_on="employee", right_on="name").drop("name", axis=1)
employee group salary
0 Bob Accounting 70000
1 Jake Engineering 80000
2 Lisa Engineering 120000
3 Sue HR 90000

left_index 및 right_index 키워드

때로는 열을 병합하는 대신 인덱스를 병합하고 싶을 수도 있습니다. 예를 들어 데이터는 다음과 같을 수 있습니다.

df1a = df1.set_index("employee")
df2a = df2.set_index("employee")
display("df1a", "df2a")

df1a

group
employee
Bob Accounting
Jake Engineering
Lisa Engineering
Sue HR

df2a

hire_date
employee
Lisa 2004
Bob 2008
Jake 2012
Sue 2014

pd.merge()left_index 및/또는 right_index 플래그를 지정하여 인덱스를 병합용 키로 사용합니다.

display("df1a", "df2a", "pd.merge(df1a, df2a, left_index=True, right_index=True)")

df1a

group
employee
Bob Accounting
Jake Engineering
Lisa Engineering
Sue HR

df2a

hire_date
employee
Lisa 2004
Bob 2008
Jake 2012
Sue 2014

pd.merge(df1a, df2a, left_index=True, right_index=True)

group hire_date
employee
Bob Accounting 2008
Jake Engineering 2012
Lisa Engineering 2004
Sue HR 2014

편의를 위해 Pandas에는 추가 키워드 없이 인덱스 기반 병합을 수행하는 DataFrame.join() 메서드가 포함되어 있습니다.

df1a.join(df2a)
group hire_date
employee
Bob Accounting 2008
Jake Engineering 2012
Lisa Engineering 2004
Sue HR 2014

인덱스와 열을 혼합하려면 left_indexright_on과 결합하거나 left_onright_index를 결합하여 원하는 동작을 얻을 수 있습니다.

display("df1a", "df3", "pd.merge(df1a, df3, left_index=True, right_on='name')")

df1a

group
employee
Bob Accounting
Jake Engineering
Lisa Engineering
Sue HR

df3

name salary
0 Bob 70000
1 Jake 80000
2 Lisa 120000
3 Sue 90000

pd.merge(df1a, df3, left_index=True, right_on='name')

group name salary
0 Accounting Bob 70000
1 Engineering Jake 80000
2 Engineering Lisa 120000
3 HR Sue 90000

이러한 옵션은 모두 여러 인덱스 및/또는 여러 열에서도 작동합니다. 이 동작에 대한 인터페이스는 매우 직관적입니다. 이에 대한 자세한 내용은 Pandas 설명서의 “병합, 조인 및 연결” 섹션을 참조하세요.

조인을 위한 집합 연산 지정

앞서 살펴본 모든 예제에서는 조인 시 고려해야 할 중요한 요소인 집합 연산의 유형을 간략하게만 언급했습니다. 이는 한쪽 키 열에는 값이 존재하지만, 다른 쪽에는 없는 경우에 해당합니다. 다음 예를 고려하십시오.

df6 = pd.DataFrame(
    {"name": ["Peter", "Paul", "Mary"], "food": ["fish", "beans", "bread"]},
    columns=["name", "food"],
)
df7 = pd.DataFrame(
    {"name": ["Mary", "Joseph"], "drink": ["wine", "beer"]}, columns=["name", "drink"]
)
display("df6", "df7", "pd.merge(df6, df7)")

df6

name food
0 Peter fish
1 Paul beans
2 Mary bread

df7

name drink
0 Mary wine
1 Joseph beer

pd.merge(df6, df7)

name food drink
0 Mary bread wine

여기서는 ‘name’ 항목 중 ’Mary’만 공통으로 가진 두 데이터 세트를 병합했습니다. 병합 결과에는 두 입력 세트의 교집합이 포함되며, 이를 내부 조인(Inner Join)이라고 합니다. 기본값은 "inner"how 키워드를 사용하여 이를 명시적으로 지정합니다.

pd.merge(df6, df7, how="inner")
name food drink
0 Mary bread wine

how 키워드에 대한 다른 옵션은 'outer', 'left''right'입니다. 외부 조인은 입력 열의 합집합에 대한 조인을 반환하고 누락된 모든 값을 NA로 채웁니다.

display("df6", "df7", "pd.merge(df6, df7, how='outer')")

df6

name food
0 Peter fish
1 Paul beans
2 Mary bread

df7

name drink
0 Mary wine
1 Joseph beer

pd.merge(df6, df7, how='outer')

name food drink
0 Peter fish NaN
1 Paul beans NaN
2 Mary bread wine
3 Joseph NaN beer

왼쪽 조인오른쪽 조인은 각각 왼쪽 항목과 오른쪽 항목에 대한 조인을 반환합니다. 예를 들어:

display("df6", "df7", "pd.merge(df6, df7, how='left')")

df6

name food
0 Peter fish
1 Paul beans
2 Mary bread

df7

name drink
0 Mary wine
1 Joseph beer

pd.merge(df6, df7, how='left')

name food drink
0 Peter fish NaN
1 Paul beans NaN
2 Mary bread wine

이제 출력 행은 왼쪽 입력의 항목에 해당합니다. 사용 how='right'도 비슷한 방식으로 작동합니다.

이러한 옵션은 모두 이전 조인 유형에 직접 적용합니다.

열 이름이 겹치는 경우: 접미사(Suffixes) 지정

마지막으로 두 입력 DataFrame의 열 이름이 충돌하는 경우가 발생합니다. 다음 예를 고려하십시오.

df8 = pd.DataFrame({"name": ["Bob", "Jake", "Lisa", "Sue"], "rank": [1, 2, 3, 4]})
df9 = pd.DataFrame({"name": ["Bob", "Jake", "Lisa", "Sue"], "rank": [3, 1, 4, 2]})
display("df8", "df9", 'pd.merge(df8, df9, on="name")')

df8

name rank
0 Bob 1
1 Jake 2
2 Lisa 3
3 Sue 4

df9

name rank
0 Bob 3
1 Jake 1
2 Lisa 4
3 Sue 2

pd.merge(df8, df9, on="name")

name rank_x rank_y
0 Bob 1 3
1 Jake 2 1
2 Lisa 3 4
3 Sue 4 2

출력에는 두 개의 충돌하는 열 이름이 있기 때문에 merge 함수는 출력 열을 고유하게 만들기 위해 자동으로 접미사 ’_x’ 및 ’_y’를 추가합니다. 이러한 기본값이 적절하지 않은 경우 suffixes 키워드를 사용하여 사용자 정의 접미사를 지정합니다:

pd.merge(df8, df9, on="name", suffixes=["_L", "_R"])
name rank_L rank_R
0 Bob 1 3
1 Jake 2 1
2 Lisa 3 4
3 Sue 4 2

이러한 접미사는 가능한 모든 조인 패턴에서 작동하며 여러 개의 겹치는 열이 있는 경우에도 작동합니다.

이러한 패턴에 대한 자세한 내용은 집계와 그룹화를 참고하세요. 관계 대수에 대해서도 더 깊이 있게 다룹니다. 또한 이러한 주제에 대한 추가 논의는 Pandas 문서의 “병합, 결합, 연결 및 비교” 섹션을 참조하세요.

예제: 미국 주별 데이터

병합 및 조인 작업은 서로 다른 소스의 데이터를 결합할 때 가장 자주 발생합니다. 여기서는 미국 주와 그 인구에 대한 일부 데이터의 예를 살펴보겠습니다. 데이터 파일은 http://github.com/jakevdp/data-USstates에서 찾을 수 있습니다.

# Following are commands to download the data
# repo = "https://raw.githubusercontent.com/jakevdp/data-USstates/master"
# !cd data && curl -O {repo}/state-population.csv
# !cd data && curl -O {repo}/state-areas.csv
# !cd data && curl -O {repo}/state-abbrevs.csv

Pandas read_csv 함수를 사용하여 세 가지 데이터 세트를 살펴보겠습니다.

pop = pd.read_csv("data/state-population.csv")
areas = pd.read_csv("data/state-areas.csv")
abbrevs = pd.read_csv("data/state-abbrevs.csv")

display("pop.head()", "areas.head()", "abbrevs.head()")

pop.head()

state/region ages year population
0 AL under18 2012 1117489.0
1 AL total 2012 4817528.0
2 AL under18 2010 1130966.0
3 AL total 2010 4785570.0
4 AL under18 2011 1125763.0

areas.head()

state area (sq. mi)
0 Alabama 52423
1 Alaska 656425
2 Arizona 114006
3 Arkansas 53182
4 California 163707

abbrevs.head()

state abbreviation
0 Alabama AL
1 Alaska AK
2 Arizona AZ
3 Arkansas AR
4 California CA

이 정보가 주어지면 상대적으로 간단한 결과를 계산한다고 가정해 보겠습니다. 즉, 2010년 인구 밀도를 기준으로 미국 주와 지역의 순위를 매깁니다. 이 결과를 찾기 위한 데이터가 분명히 여기에 있지만 그렇게 하려면 데이터 세트를 결합해야 합니다.

인구 DataFrame 내의 전체 상태 이름을 제공하는 다대일 병합부터 시작하겠습니다. popstate/region 열과 abbrevsabbreviation 열을 기준으로 병합하려고 합니다. 일치하지 않는 레이블로 인해 데이터가 삭제되지 않도록 how='outer'를 사용합니다.

merged = pd.merge(
    pop, abbrevs, how="outer", left_on="state/region", right_on="abbreviation"
)
merged = merged.drop("abbreviation", axis=1)  # drop duplicate info
merged.head()
state/region ages year population state
0 AL under18 2012 1117489.0 Alabama
1 AL total 2012 4817528.0 Alabama
2 AL under18 2010 1130966.0 Alabama
3 AL total 2010 4785570.0 Alabama
4 AL under18 2011 1125763.0 Alabama

데이터에 누락된 부분이 있는지 확인해 보겠습니다. Null 값이 있는 행을 찾아보면 됩니다.

merged.isnull().any()
state/region    False
ages            False
year            False
population       True
state            True
dtype: bool

인구수(population) 데이터 중 일부가 Null입니다. 어떤 데이터인지 확인해 보겠습니다.

merged[merged["population"].isnull()].head()
state/region ages year population state
2448 PR under18 1990 NaN NaN
2449 PR total 1990 NaN NaN
2450 PR total 1991 NaN NaN
2451 PR under18 1991 NaN NaN
2452 PR total 1993 NaN NaN

누락된 인구수 데이터는 모두 2000년 이전의 푸에르토리코 자료인 것으로 보입니다. 이는 원본 소스에서 이 데이터를 사용할 수 없기 때문일 수 있습니다.

더 중요한 것은 새로운 state 항목 중 일부도 null이라는 점입니다. 이는 abbrevs 키에 해당 항목이 없다는 의미입니다! 이 일치 항목이 없는 지역을 찾아보겠습니다.

merged.loc[merged["state"].isnull(), "state/region"].unique()
array(['PR', 'USA'], dtype=object)

문제를 빠르게 추론합니다. 인구 데이터에는 푸에르토리코(PR) 및 미국 전체(USA)에 대한 항목이 포함되어 있지만 이러한 항목은 주 약어 키에 표시되지 않습니다. 적절한 항목을 입력하면 이러한 문제를 신속하게 해결합니다.

merged.loc[merged["state/region"] == "PR", "state"] = "Puerto Rico"
merged.loc[merged["state/region"] == "USA", "state"] = "United States"
merged.isnull().any()
state/region    False
ages            False
year            False
population       True
state           False
dtype: bool

state 열에 더 이상 null이 없습니다. 모든 설정이 완료되었습니다!

이제 유사한 절차를 사용하여 결과를 영역 데이터와 병합합니다. 결과를 검토해 보면 다음 두 항목 모두 state 열에 조인하려고 합니다.

final = pd.merge(merged, areas, on="state", how="left")
final.head()
state/region ages year population state area (sq. mi)
0 AL under18 2012 1117489.0 Alabama 52423.0
1 AL total 2012 4817528.0 Alabama 52423.0
2 AL under18 2010 1130966.0 Alabama 52423.0
3 AL total 2010 4785570.0 Alabama 52423.0
4 AL under18 2011 1125763.0 Alabama 52423.0

다시 한번, 불일치가 있는지 확인하기 위해 null을 확인해 보겠습니다.

final.isnull().any()
state/region     False
ages             False
year             False
population        True
state            False
area (sq. mi)     True
dtype: bool

‘area’ 열에 null이 있습니다. 여기에서 어떤 지역이 무시되었는지 확인합니다.

final["state"][final["area (sq. mi)"].isnull()].unique()
array(['United States'], dtype=object)

우리의 areas````DataFrame에는 미국 전체 지역이 포함되어 있지 않습니다. 예를 들어 모든 주 지역의 합계를 사용하여 적절한 값을 삽입할 수 있지만 이 경우 미국 전체의 인구 밀도가 현재 논의와 관련이 없기 때문에 null 값을 삭제하겠습니다.

final.dropna(inplace=True)
final.head()
state/region ages year population state area (sq. mi)
0 AL under18 2012 1117489.0 Alabama 52423.0
1 AL total 2012 4817528.0 Alabama 52423.0
2 AL under18 2010 1130966.0 Alabama 52423.0
3 AL total 2010 4785570.0 Alabama 52423.0
4 AL under18 2011 1125763.0 Alabama 52423.0

이제 필요한 모든 데이터가 확보되었습니다. 관심 있는 질문에 답하기 위해 먼저 데이터 중 2010년에 해당하는 부분과 전체 인구를 선택해 보겠습니다. 이 작업을 빠르게 수행하기 위해 query 함수를 사용하겠습니다(이를 위해서는 NumExpr 패키지가 설치되어 있어야 합니다. 고성능 Pandas: eval()query() 참조):

data2010 = final.query("year == 2010 & ages == 'total'")
data2010.head()
state/region ages year population state area (sq. mi)
3 AL total 2010 4785570.0 Alabama 52423.0
91 AK total 2010 713868.0 Alaska 656425.0
101 AZ total 2010 6408790.0 Arizona 114006.0
189 AR total 2010 2922280.0 Arkansas 53182.0
197 CA total 2010 37333601.0 California 163707.0

이제 인구 밀도를 계산하여 순서대로 표시해 보겠습니다. 먼저 상태에 대한 데이터를 다시 색인화한 다음 결과를 계산하겠습니다.

data2010.set_index("state", inplace=True)
density = data2010["population"] / data2010["area (sq. mi)"]
density.sort_values(ascending=False, inplace=True)
density.head()
state
District of Columbia    8898.897059
Puerto Rico             1058.665149
New Jersey              1009.253268
Rhode Island             681.339159
Connecticut              645.600649
dtype: float64

그 결과 미국 주와 워싱턴 DC, 푸에르토리코의 2010년 인구 밀도(평방 마일당 주민 수) 순으로 순위가 매겨졌습니다. 이 데이터 세트에서 가장 밀도가 높은 지역은 워싱턴 DC(즉, 컬럼비아 특별구)라는 것을 확인합니다. 주 중에서 밀도가 가장 높은 곳은 뉴저지주입니다.

목록의 끝을 확인할 수도 있습니다.

density.tail()
state
South Dakota    10.583512
North Dakota     9.537565
Montana          6.736171
Wyoming          5.768079
Alaska           1.087509
dtype: float64

지금까지 밀도가 가장 낮은 주는 알래스카로, 평균적으로 평방 마일당 거주자 수가 1명을 약간 넘는다는 것을 확인합니다.

이러한 유형의 데이터 병합은 실제 데이터 원본을 사용하여 질문에 답하려고 할 때 일반적인 작업입니다. 이 예를 통해 데이터에서 통찰력을 얻기 위해 지금까지 다룬 도구를 결합할 수 있는 몇 가지 방법에 대한 아이디어를 얻었기를 바랍니다.