7.10 組合數(shù)據(jù)集:合并和連接
原文:Combining Datasets: Merge and Join
譯者:飛龍
協(xié)議:CC BY-NC-SA 4.0
本節(jié)是《Python 數(shù)據(jù)科學手冊》(Python Data Science Handbook)的摘錄瘟檩。
Pandas 提供的一個基本特性原茅,是內(nèi)存中的高性能的連接和合并操作。如果你曾經(jīng)使用過數(shù)據(jù)庫撬呢,那么你應該熟悉這種類型的數(shù)據(jù)交互。它的主要接口是pd.merge
函數(shù)妆兑,我們將看到幾個在實踐中如何工作的例子魂拦。
為方便起見,我們將從重新定義上一節(jié)的display()
函數(shù)開始:
import pandas as pd
import numpy as np
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)
關系代數(shù)
pd.merge()
中實現(xiàn)的行為搁嗓,是所謂的關系代數(shù)的一個子集芯勘,它是一組用于操縱關系數(shù)據(jù)的形式規(guī)則,并形成了大多數(shù)數(shù)據(jù)庫中可用操作的概念基礎腺逛。關系代數(shù)方法的優(yōu)勢在于它提出了幾種原始操作荷愕,這些操作成為任何數(shù)據(jù)集上更復雜操作的積木。擁有在數(shù)據(jù)庫或其他程序中高效實現(xiàn)的基本操作詞典棍矛,可以執(zhí)行各種相當復雜的復合操作安疗。
Pandas 在pd.merge()
函數(shù)和Series
和Dataframe
的相關join()
方法中,實現(xiàn)了幾個基本構(gòu)建塊够委。正如我們將看到的荐类,這些可以讓你有效地鏈接來自不同來源的數(shù)據(jù)。
連接的分類
pd.merge()
函數(shù)實現(xiàn)了許多類型的連接:一對一茁帽,多對一和多對多連接玉罐。通過以相同方式調(diào)用pd.merge()
接口,來訪問所有三種類型的連接潘拨;執(zhí)行的連接類型取決于輸入數(shù)據(jù)的形式吊输。這里我們將展示三種合并的簡單示例,并在下面進一步討論詳細選項铁追。
一對一連接
也許最簡單的合并表達式是一對一連接季蚂,這在很多方面與“數(shù)據(jù)集的組合:連接和附加”中的按列連接非常相似。。作為一個具體的例子扭屁,考慮以下兩個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()
函數(shù):
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()
函數(shù)識別疯搅,每個DataFrame
都有一個employee
列濒生,并使用該列作為鍵自動連接。合并的結(jié)果是一個新的DataFrame
幔欧,它組合了兩個輸入的信息罪治。
請注意,每列中的條目順序不一定得到保留:在這種情況下礁蔗,employee
列的順序在df1
和df2
之間有所不同觉义。pd.merge()
函數(shù)正確地解釋了這一點。另外浴井,請記住晒骇,合并一般會丟棄索引,除了在索引合并的特殊情況下(參見left_index
和right_index
關鍵字磺浙,之后討論)洪囤。
多對一連接
多對一連接中,兩個鍵列中的一個包含重復條目撕氧。對于多對一的情況瘤缩,生成的DataFrame
將保留適當?shù)闹貜蜅l目÷啄啵考慮以下多對一連接的示例:
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
擁有帶有supervisor
信息的附加列剥啤,其中信息在輸入所需的一個或多個位置重復。
多對多連接
多對多連接在概念上有點令人困惑不脯,但仍然有很好的定義府怯。如果左側(cè)和右側(cè)數(shù)組中的鍵列都包含重復項,則結(jié)果是多對多合并防楷。
結(jié)合一個具體的例子可能是最清楚的牺丙。考慮以下內(nèi)容域帐,我們有一個DataFrame
赘被,展示了與特定分組相關的一項或多項技能是整。通過執(zhí)行多對多連接肖揣,我們可以恢復與任何個人相關的技能:
df5 = pd.DataFrame({'group': ['Accounting', 'Accounting',
'Engineering', 'Engineering', 'HR', 'HR'],
'skills': ['math', 'spreadsheets', 'coding', 'linux',
'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 | coding |
3 | Engineering | linux |
4 | HR | spreadsheets |
5 | HR | organization |
pd.merge(df1, df5)
:
employee | group | skills | |
---|---|---|---|
0 | Bob | Accounting | math |
1 | Bob | Accounting | spreadsheets |
2 | Jake | Engineering | coding |
3 | Jake | Engineering | linux |
4 | Lisa | Engineering | coding |
5 | Lisa | Engineering | linux |
6 | Sue | HR | spreadsheets |
7 | Sue | HR | organization |
這三種類型的連接可以與其他 Pandas 工具一起使用,以實現(xiàn)各種功能浮入。但實際上龙优,數(shù)據(jù)集很少像我們在這里使用的那樣干凈。在下一節(jié)中,我們將考慮pd.merge()
提供的一些選項彤断,使你能夠調(diào)整連接操作的工作方式野舶。
指定合并鍵
我們已經(jīng)看到了pd.merge()
的默認行為:它在兩個輸入之間查找一個或多個匹配的列名,并將其用作鍵宰衙。但是平道,通常列名稱不能很好地匹配,而pd.merge()
提供了各種處理它的選項供炼。
on
關鍵字
Most simply, you can explicitly specify the name of the key column using the on
keyword, which takes a column name or a list of column names:
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 |
僅當左側(cè)和右側(cè)DataFrame
都具有指定的列名時一屋,此選項才有效。
left_on
和right_on
關鍵字
有時你可能希望合并具有不同列名的兩個數(shù)據(jù)集袋哼;例如冀墨,我們可能有一個數(shù)據(jù)集,其中員工姓名被標記為name
而不是employee
涛贯。在這種情況下诽嘉,我們可以使用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 |
結(jié)果有一個冗余列,如果需要我們可以刪除 - 例如弟翘,通過使用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
關鍵字
有時虫腋,你寧愿按索引合并,而不是按列合并稀余。例如岔乔,你的數(shù)據(jù)可能如下所示:
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 | ||
Lisa | Engineering | 2004 |
Bob | Accounting | 2008 |
Jake | Engineering | 2012 |
Sue | HR | 2014 |
為方便起見滚躯,DataFrame`實現(xiàn)
join()``方法雏门,該方法執(zhí)行的合并默認為連接索引:
display('df1a', 'df2a', 'df1a.join(df2a)')
df1a
:
group | |
---|---|
employee | |
Bob | Accounting |
Jake | Engineering |
Lisa | Engineering |
Sue | HR |
df2a
:
hire_date | |
---|---|
employee | |
Lisa | 2004 |
Bob | 2008 |
Jake | 2012 |
Sue | 2014 |
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
結(jié)合起來掸掏,來獲得所需的行為:
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 |
所有這些選項也適用于多重索引和/或多個列茁影;這種行為的接口非常直觀。此內(nèi)容的更多信息丧凤,請參閱 Pandas 文檔的“合并募闲,連接(Join)和連接(concat)”一節(jié)。
為連接指定集合運算
在前面的所有例子中愿待,我們在執(zhí)行連接時掩蓋了一個重要的考慮因素:連接中使用的集合運算的類型浩螺。當一個值出現(xiàn)在一個鍵列而不出現(xiàn)在另一個鍵列中時,會出現(xiàn)此情況仍侥。 考慮這個例子:
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 |
在這里要出,我們合并了兩個數(shù)據(jù)集,它們只有一個相同的name
條目:Mary
农渊。默認情況下患蹂,結(jié)果包含兩組輸入的交集;這就是所謂的內(nèi)連接。我們可以使用how
關鍵字明確指定它传于,默認為"inner"
:
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 |
左連接和右連接分別返回左側(cè)條目和右側(cè)條目上的連接平挑。例如:
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 |
輸出行現(xiàn)在對應于左輸入中的條目。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
函數(shù)會自動附加后綴_x
或_y
來使輸出列唯一檐嚣。如果這些默認值不合適助泽,可以使用suffixes
關鍵字指定自定義后綴:
display('df8', 'df9', 'pd.merge(df8, df9, on="name", suffixes=["_L", "_R"])')
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", suffixes=["_L", "_R"])
:
name | rank_L | rank_R | |
---|---|---|---|
0 | Bob | 1 | 3 |
1 | Jake | 2 | 1 |
2 | Lisa | 3 | 4 |
3 | Sue | 4 | 2 |
這些后綴適用于任何可能的連接模式,并且如果存在多個重疊列嚎京,則也有效嗡贺。這些模式的更多信息,請參閱“聚合和分組”鞍帝,其中我們深入研究了關系代數(shù)诫睬。這些主題的進一步討論,請參閱[Pandas“合并帕涌,連接(Join)和連接(Concatenate)文檔”摄凡。
示例:美國各州數(shù)據(jù)
在組合來自不同來源的數(shù)據(jù)時,合并和連接操作最常出現(xiàn)蚓曼。在這里亲澡,我們將考慮美國各州及其人口數(shù)據(jù)的一些例子。數(shù)據(jù)文件可以在 http://github.com/jakevdp/data-USstates/ 找到:
# 下面是下載數(shù)據(jù)的 shell 命令
# !curl -O https://raw.githubusercontent.com/jakevdp/data-USstates/master/state-population.csv
# !curl -O https://raw.githubusercontent.com/jakevdp/data-USstates/master/state-areas.csv
# !curl -O https://raw.githubusercontent.com/jakevdp/data-USstates/master/state-abbrevs.csv
讓我們看一下三個數(shù)據(jù)集纫版,使用 Pandas read_csv()
函數(shù):
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 |
根據(jù)這些信息床绪,我們想要計算一個相對簡單的結(jié)果:根據(jù) 2010 年人口密度對美國各州和地區(qū)進行排名。顯然其弊,我們在這里擁有用于找到這個結(jié)果的數(shù)據(jù)癞己,但是我們必須結(jié)合數(shù)據(jù)集來找到結(jié)果。
我們將從多對一合并開始梭伐,它將向我們提供人口DataFrame
中的完整的州名痹雅。我們想要根據(jù)pop
的state/region
列和abbrevs
的abbreviation
列進行合并。我們將使用how ='outer'
來確保沒有數(shù)據(jù)因標簽不匹配而被丟棄籽御。
merged = pd.merge(pop, abbrevs, how='outer',
left_on='state/region', right_on='abbreviation')
merged = merged.drop('abbreviation', 1) # 丟棄重復的數(shù)據(jù)
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 |
讓我們仔細檢查這里是否存在任何不匹配练慕,我們可以通過查找?guī)в锌罩档男衼韺崿F(xiàn):
merged.isnull().any()
'''
state/region False
ages False
year False
population True
state True
dtype: bool
'''
一些population
信息為空惰匙;讓我們弄清楚這些是什么技掏!
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 年之前的波多黎各铃将;這可能是由于數(shù)據(jù)從原始來源無法獲得。
更重要的是哑梳,我們還看到一些新的state
條目也是控制劲阎,這意味著abbrevs
鍵中沒有相應的條目!讓我們弄清楚哪些地區(qū)缺少這種匹配:
merged.loc[merged['state'].isnull(), 'state/region'].unique()
# array(['PR', 'USA'], dtype=object)
我們可以快速推斷出這個問題:我們的人口數(shù)據(jù)包括波多黎各(PR)和整個美國(美國)的條目鸠真,而這些條目沒有出現(xiàn)在州縮寫的鍵中悯仙。我們可以通過填充適當?shù)臈l目來快速解決這些問題。
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
列中沒有更多的空值:我們?nèi)几愣耍?/p>
現(xiàn)在我們可以使用類似的過程吠卷,來合并結(jié)果和面積數(shù)據(jù)锡垄。檢查我們的結(jié)果吉嫩,我們將想要連接二者中的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 |
再次云挟,讓我們檢查空值來查看是否存在任何不匹配:
final.isnull().any()
'''
state/region False
ages False
year False
population True
state False
area (sq. mi) True
dtype: bool
'''
area
列中有空值; 我們可以看看這里忽略了哪些區(qū)域:
final['state'][final['area (sq. mi)'].isnull()].unique()
# array(['United States'], dtype=object)
我們看到我們的areas DataFrame
不包含整個美國的面積求厕。我們可以插入適當?shù)闹担ɡ缗璧ⅲ褂盟兄莸拿娣e總和)惠奸,但在這種情況下勺拣,我們只會刪除空值孕似,因為整個美國的人口密度與我們當前的討論無關:
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 |
現(xiàn)在我們擁有了所需的所有數(shù)據(jù)送朱。 為了回答感興趣的問題搞坝,讓我們首先選擇對應 2000 年的數(shù)據(jù)部分和總?cè)丝谏η础N覀儗⑹褂?code>query()函數(shù)快速執(zhí)行此操作(這需要安裝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 |
現(xiàn)在讓我們計算人口密度并按順序顯示桩撮。我們首先重索引各州數(shù)據(jù)敦第,然后計算結(jié)果:
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
'''
結(jié)果是美國各州,華盛頓特區(qū)和波多黎各按其 2010 年人口密度的排名店量,以每平方英里居民為單位申尼。我們可以看到,到目前為止垫桂,該數(shù)據(jù)集中最密集的區(qū)域是華盛頓特區(qū)(即哥倫比亞特區(qū))师幕;在各州之間,最密集的是新澤西州诬滩。
我們還可以查看列表的末尾:
density.tail()
'''
state
South Dakota 10.583512
North Dakota 9.537565
Montana 6.736171
Wyoming 5.768079
Alaska 1.087509
dtype: float64
'''
到目前為止霹粥,我們看到最不密集的州是阿拉斯加州,每平方英里平均略多于一個居民疼鸟。
嘗試使用真實數(shù)據(jù)源回答問題時后控,這種混亂的數(shù)據(jù)合并是一項常見任務。我希望這個例子讓你了解空镜,如何組合我們所涵蓋的工具浩淘,來從你的數(shù)據(jù)中獲得見解捌朴!