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)데이터 결합: 병합(Merge)과 조인(Join)
Pandas가 제공하는 중요한 기능 중 하나는 고성능 메모리 내 조인 및 병합 기능으로, 데이터베이스 작업을 해 본 적이 있다면 익숙할 것입니다. 이에 대한 주요 인터페이스는 pd.merge 함수이며 실제로 어떻게 작동하는지 예제를 통해 살펴보겠습니다.
편의상 일반적인 import 이후 이전 장의 display 함수를 다시 정의하겠습니다.
관계 대수(Relational Algebra)
’pd.merge’에 구현된 동작은 관계 대수(Relational Algebra)의 일부입니다. 이는 대부분의 데이터베이스에서 사용할 수 있는 작업의 개념적 기초를 형성하는 관계형 데이터를 조작하기 위한 공식 규칙 세트입니다. 관계 대수 방식의 강점은, 복잡한 데이터 작업을 구성하는 몇 가지 핵심적인 기본 연산을 제공한다는 점에 있습니다. 데이터베이스나 기타 프로그램에서 효율적으로 구현된 기본 작업 어휘를 사용하면 상당히 복잡한 복합 작업을 광범위하게 수행합니다.
Pandas는 pd.merge 함수와 Series 및 DataFrame 개체의 관련 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 함수는 각 DataFrame에 employee 열이 있음을 인식하고 이 열을 키로 사용하여 자동으로 조인합니다. 병합의 결과는 두 입력의 정보를 결합하는 새로운 ‘DataFrame’입니다. 각 열의 항목 순서가 반드시 유지되는 것은 아닙니다. 이 경우 employee 열의 순서는 df1과 df2에서 다르며 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_on 및 right_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_index를 right_on과 결합하거나 left_on과 right_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.csvPandas 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 내의 전체 상태 이름을 제공하는 다대일 병합부터 시작하겠습니다. pop의 state/region 열과 abbrevs의 abbreviation 열을 기준으로 병합하려고 합니다. 일치하지 않는 레이블로 인해 데이터가 삭제되지 않도록 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명을 약간 넘는다는 것을 확인합니다.
이러한 유형의 데이터 병합은 실제 데이터 원본을 사용하여 질문에 답하려고 할 때 일반적인 작업입니다. 이 예를 통해 데이터에서 통찰력을 얻기 위해 지금까지 다룬 도구를 결합할 수 있는 몇 가지 방법에 대한 아이디어를 얻었기를 바랍니다.