Pandas?合并數(shù)據(jù)集merge?和?join的使用

Pandas 提供了一個(gè)重要的功能,即高性能的內(nèi)存中連接(join)和合并(merge)操作,如果你曾經(jīng)使用過數(shù)據(jù)庫,可能已經(jīng)很熟悉這些操作。
主要的接口是 pd.merge 函數(shù),接下來我們將通過一些示例來了解它的實(shí)際用法。
為了方便起見,我們會(huì)在常規(guī)導(dǎo)入之后再次定義上一章中的 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)
關(guān)系代數(shù)
pd.merge 實(shí)現(xiàn)的行為是關(guān)系代數(shù)的一部分。關(guān)系代數(shù)是一套用于操作關(guān)系型數(shù)據(jù)的正式規(guī)則,是大多數(shù)數(shù)據(jù)庫操作的概念基礎(chǔ)。
關(guān)系代數(shù)方法的優(yōu)勢(shì)在于它提出了若干基本操作,這些操作成為對(duì)任何數(shù)據(jù)集進(jìn)行更復(fù)雜操作的構(gòu)建模塊。
只要在數(shù)據(jù)庫或其他程序中高效實(shí)現(xiàn)了這些基本操作,就可以執(zhí)行各種相當(dāng)復(fù)雜的復(fù)合操作。
Pandas 在 pd.merge 函數(shù)以及 Series 和 DataFrame 對(duì)象的相關(guān) join 方法中實(shí)現(xiàn)了這些基本構(gòu)建模塊中的幾個(gè)。
正如你將看到的,這些方法可以高效地將來自不同來源的數(shù)據(jù)關(guān)聯(lián)起來。
連接的類別
pd.merge 函數(shù)實(shí)現(xiàn)了多種類型的連接:一對(duì)一、多對(duì)一 和 多對(duì)多。
這三種連接類型都可以通過相同的 pd.merge 接口調(diào)用實(shí)現(xiàn);實(shí)際執(zhí)行哪種連接,取決于輸入數(shù)據(jù)的形式。
我們將從這三種合并類型的簡單示例開始,稍后再討論更詳細(xì)的選項(xiàng)。
一對(duì)一連接
也許最簡單的合并類型就是一對(duì)一連接,這在很多方面類似于你在合并數(shù)據(jù)集:concat 和 append中看到的按列拼接。
舉個(gè)具體的例子,考慮下面兩個(gè) DataFrame 對(duì)象,它們包含了公司中幾位員工的信息:
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 |
要將這些信息合并到一個(gè) 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ù)會(huì)自動(dòng)識(shí)別每個(gè) DataFrame 中的 employee 列,并以此作為鍵進(jìn)行連接。
合并的結(jié)果是一個(gè)新的 DataFrame,它將兩個(gè)輸入的數(shù)據(jù)整合在一起。
請(qǐng)注意,每一列中的條目順序不一定會(huì)被保留:在本例中,employee 列在 df1 和 df2 中的順序不同,而 pd.merge 函數(shù)能夠正確處理這一點(diǎn)。
另外需要注意的是,合并操作通常會(huì)丟棄索引,除非使用按索引合并(稍后會(huì)討論 left_index 和 right_index 關(guān)鍵字)。
多對(duì)一連接
多對(duì)一連接是指兩個(gè)鍵列中的一個(gè)包含重復(fù)項(xiàng)的連接。
對(duì)于多對(duì)一連接,結(jié)果 DataFrame 會(huì)適當(dāng)?shù)乇A暨@些重復(fù)項(xiàng)。
請(qǐng)看下面關(guān)于多對(duì)一連接的示例:
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 |
結(jié)果的 DataFrame 會(huì)多出一列 “supervisor”(主管)信息,其中的信息會(huì)根據(jù)輸入數(shù)據(jù)的需要在一個(gè)或多個(gè)位置重復(fù)出現(xiàn)。
多對(duì)多連接
多對(duì)多連接在概念上可能有些令人困惑,但它們依然有明確的定義。
如果左右數(shù)組中的鍵列都包含重復(fù)項(xiàng),那么結(jié)果就是多對(duì)多合并。
通過具體的例子可以更清楚地理解這一點(diǎn)。
請(qǐng)看下面的例子,我們有一個(gè) DataFrame,顯示了每個(gè)小組關(guān)聯(lián)的一項(xiàng)或多項(xiàng)技能。
通過執(zhí)行多對(duì)多連接,我們可以獲得與每個(gè)個(gè)人相關(guān)的技能信息:
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 工具結(jié)合使用,實(shí)現(xiàn)各種功能。
但在實(shí)際應(yīng)用中,數(shù)據(jù)集很少像我們這里演示的那樣干凈整齊。
在接下來的部分,我們將介紹 pd.merge 提供的一些選項(xiàng),這些選項(xiàng)可以幫助你調(diào)整連接操作的具體方式。
指定合并鍵
我們已經(jīng)看到了 pd.merge 的默認(rèn)行為:它會(huì)在兩個(gè)輸入數(shù)據(jù)中查找一個(gè)或多個(gè)匹配的列名,并將其作為連接鍵。
然而,很多時(shí)候列名并不會(huì)如此完美地匹配,pd.merge 提供了多種選項(xiàng)來處理這種情況。
on 關(guān)鍵字
最簡單的方式是使用 on 關(guān)鍵字顯式指定連接鍵的列名。on 可以接受一個(gè)列名或列名列表:
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 |
此選項(xiàng)僅在左右兩個(gè) DataFrame 都包含指定的列名時(shí)有效。
left_on 和 right_on 關(guān)鍵字
有時(shí)你可能希望合并兩個(gè)具有不同列名的數(shù)據(jù)集;例如,我們可能有一個(gè)數(shù)據(jù)集,其中員工姓名的列名是 “name” 而不是 “employee”。
在這種情況下,我們可以使用 left_on 和 right_on 關(guān)鍵字來分別指定兩個(gè)列名:
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é)果中有一個(gè)多余的列,如果需要,可以通過 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 關(guān)鍵字
有時(shí)候,你可能希望根據(jù)索引而不是某一列來進(jìn)行合并。
例如,你的數(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 參數(shù),將索引作為合并的鍵來使用:
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() 方法,它可以在不需要額外關(guān)鍵字的情況下基于索引進(jìn)行合并:
df1a.join(df2a)
| group | hire_date | |
|---|---|---|
| employee | ||
| Bob | Accounting | 2008 |
| Jake | Engineering | 2012 |
| Lisa | Engineering | 2004 |
| Sue | HR | 2014 |
如果你希望混合使用索引和列進(jìn)行合并,可以結(jié)合使用 left_index 與 right_on,或 left_on 與 right_index,以實(shí)現(xiàn)所需的行為:
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 |
所有這些選項(xiàng)同樣適用于多個(gè)索引和/或多列;其接口設(shè)計(jì)非常直觀易用。
更多相關(guān)內(nèi)容,請(qǐng)參閱 Pandas 文檔中的“合并、連接與拼接”部分。
為連接指定集合運(yùn)算方式
在之前的所有示例中,我們都忽略了執(zhí)行連接時(shí)一個(gè)重要的考慮因素:連接中所使用的集合運(yùn)算類型。
當(dāng)某個(gè)值出現(xiàn)在一個(gè)鍵列中但未出現(xiàn)在另一個(gè)鍵列時(shí),這個(gè)問題就會(huì)出現(xiàn)。請(qǐng)看下面的例子:
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 |
這里我們合并了兩個(gè)數(shù)據(jù)集,它們只有一個(gè)共同的 “name” 條目:Mary。
默認(rèn)情況下,結(jié)果只包含兩個(gè)輸入集合的交集;這就是所謂的內(nèi)連接(inner join)。
我們可以通過 how 關(guān)鍵字顯式指定這一點(diǎn),how 的默認(rèn)值為 "inner":
pd.merge(df6, df7, how='inner')
| name | food | drink | |
|---|---|---|---|
| 0 | Mary | bread | wine |
how 關(guān)鍵字的其他選項(xiàng)包括 'outer'、'left' 和 'right'。
外連接(outer join)會(huì)返回輸入列的并集,并用 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 | Joseph | NaN | beer |
| 1 | Mary | bread | wine |
| 2 | Paul | beans | NaN |
| 3 | Peter | fish | NaN |
左連接(left join)和右連接(right join)分別返回以左側(cè)條目或右側(cè)條目為基礎(chǔ)的連接結(jié)果。
例如:
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)在對(duì)應(yīng)于左側(cè)輸入中的條目。使用 how='right' 的方式也類似。
所有這些選項(xiàng)都可以直接應(yīng)用于前面介紹的各種連接類型。
列名重疊:suffixes 關(guān)鍵字
最后,你可能會(huì)遇到兩個(gè)輸入的 DataFrame 存在列名沖突的情況。
請(qǐng)看下面的例子:
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 |
由于輸出結(jié)果中會(huì)有兩個(gè)沖突的列名,merge 函數(shù)會(huì)自動(dòng)在輸出列名后添加 _x 和 _y 后綴,以確保列名唯一。
如果默認(rèn)的后綴不合適,可以通過 suffixes 關(guān)鍵字自定義后綴:
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 |
這些后綴適用于所有可能的連接方式,并且在存在多個(gè)重疊列時(shí)同樣有效。
我們將在其中更深入地探討關(guān)系代數(shù)。
示例:美國各州數(shù)據(jù)
合并和連接操作最常見于將來自不同來源的數(shù)據(jù)組合在一起。
這里我們將以美國各州及其人口數(shù)據(jù)為例進(jìn)行說明。
相關(guān)數(shù)據(jù)文件可在 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 函數(shù)來查看這三個(gè)數(shù)據(jù)集:
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ù)上述信息,假設(shè)我們想要計(jì)算一個(gè)相對(duì)簡單的結(jié)果:按 2010 年人口密度對(duì)美國各州和領(lǐng)地進(jìn)行排名。
我們已經(jīng)擁有了實(shí)現(xiàn)這一目標(biāo)所需的數(shù)據(jù),但需要將這些數(shù)據(jù)集進(jìn)行合并。
我們首先進(jìn)行一次多對(duì)一合并,以便在人口 DataFrame 中獲得完整的州名。
我們希望基于 pop 的 state/region 列和 abbrevs 的 abbreviation 列進(jìn)行合并。
我們將使用 how='outer',以確保不會(huì)因?yàn)闃?biāo)簽不匹配而丟棄任何數(shù)據(jù):
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 | AK | total | 1990 | 553290.0 | Alaska |
| 1 | AK | under18 | 1990 | 177502.0 | Alaska |
| 2 | AK | total | 1992 | 588736.0 | Alaska |
| 3 | AK | under18 | 1991 | 182180.0 | Alaska |
| 4 | AK | under18 | 1992 | 184878.0 | Alaska |
讓我們仔細(xì)檢查一下是否存在不匹配的情況,可以通過查找包含空值的行來實(shí)現(xiàn):
merged.isnull().any()
state/region False ages False year False population True state True dtype: bool
有些 population(人口)值是空的;讓我們找出這些值對(duì)應(yīng)的是哪些數(shù)據(jù)!
merged[merged['population'].isnull()].head()
| state/region | ages | year | population | state | |
|---|---|---|---|---|---|
| 1872 | PR | under18 | 1990 | NaN | NaN |
| 1873 | PR | total | 1990 | NaN | NaN |
| 1874 | PR | total | 1991 | NaN | NaN |
| 1875 | PR | under18 | 1991 | NaN | NaN |
| 1876 | PR | total | 1993 | NaN | NaN |
所有人口為 null 的值似乎都來自 2000 年之前的波多黎各;這很可能是因?yàn)樵紨?shù)據(jù)源中沒有這些數(shù)據(jù)。
更重要的是,我們發(fā)現(xiàn)有些新的 state 條目也是 null,這意味著在 abbrevs 鍵中沒有對(duì)應(yīng)的條目!
讓我們找出哪些地區(qū)缺少這種匹配:
merged.loc[merged['state'].isnull(), 'state/region'].unique()
array(['PR', 'USA'], dtype=object)
我們可以很快推斷出問題所在:我們的人口數(shù)據(jù)中包含了波多黎各(PR)和美國整體(USA)的條目,而這些條目在州縮寫鍵中并未出現(xiàn)。
我們可以通過補(bǔ)充合適的條目來快速修復(fù)這個(gè)問題:
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 列中已無空值:一切準(zhǔn)備就緒!
現(xiàn)在我們可以用類似的方法將結(jié)果與面積數(shù)據(jù)進(jìn)行合并。
檢查我們的結(jié)果后,我們會(huì)希望在兩個(gè)數(shù)據(jù)集中都以 state 列作為連接鍵:
final = pd.merge(merged, areas, on='state', how='left') final.head()
| state/region | ages | year | population | state | area (sq. mi) | |
|---|---|---|---|---|---|---|
| 0 | AK | total | 1990 | 553290.0 | Alaska | 656425.0 |
| 1 | AK | under18 | 1990 | 177502.0 | Alaska | 656425.0 |
| 2 | AK | total | 1992 | 588736.0 | Alaska | 656425.0 |
| 3 | AK | under18 | 1991 | 182180.0 | Alaska | 656425.0 |
| 4 | AK | under18 | 1992 | 184878.0 | Alaska | 656425.0 |
再次檢查是否存在空值,以確定是否有不匹配的情況:
在 area 列中存在空值;我們可以查看一下哪些地區(qū)在這里被忽略了:
final['state'][final['area (sq. mi)'].isnull()].unique()
array(['United States'], dtype=object)
我們發(fā)現(xiàn) areas 這個(gè) DataFrame 并沒有包含美國整體的面積數(shù)據(jù)。
我們可以插入一個(gè)合適的值(例如所有州面積的總和),但在這里我們只需刪除這些空值,因?yàn)檎麄€(gè)美國的人口密度并不是我們當(dāng)前討論的重點(diǎn):
final.dropna(inplace=True) final.head()
| state/region | ages | year | population | state | area (sq. mi) | |
|---|---|---|---|---|---|---|
| 0 | AK | total | 1990 | 553290.0 | Alaska | 656425.0 |
| 1 | AK | under18 | 1990 | 177502.0 | Alaska | 656425.0 |
| 2 | AK | total | 1992 | 588736.0 | Alaska | 656425.0 |
| 3 | AK | under18 | 1991 | 182180.0 | Alaska | 656425.0 |
| 4 | AK | under18 | 1992 | 184878.0 | Alaska | 656425.0 |
現(xiàn)在我們已經(jīng)擁有了所需的全部數(shù)據(jù)。為了回答我們關(guān)心的問題,首先需要選取年份為 2010 且人口類型為總?cè)丝诘臄?shù)據(jù)部分。
我們將使用 query 函數(shù)來快速完成這一操作(這需要安裝 NumExpr 包:
data2010 = final.query("year == 2010 & ages == 'total'")
data2010.head()
| state/region | ages | year | population | state | area (sq. mi) | |
|---|---|---|---|---|---|---|
| 43 | AK | total | 2010 | 713868.0 | Alaska | 656425.0 |
| 51 | AL | total | 2010 | 4785570.0 | Alabama | 52423.0 |
| 141 | AR | total | 2010 | 2922280.0 | Arkansas | 53182.0 |
| 149 | AZ | total | 2010 | 6408790.0 | Arizona | 114006.0 |
| 197 | CA | total | 2010 | 37333601.0 | California | 163707.0 |
現(xiàn)在讓我們計(jì)算人口密度并按順序顯示結(jié)果。
我們將首先以州為索引重新排列數(shù)據(jù),然后計(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ù))排序的排名。
可以看到,在這個(gè)數(shù)據(jù)集中,人口密度最高的地區(qū)是華 盛 頓特區(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
我們可以看到,人口密度最低的州遠(yuǎn)遠(yuǎn)是阿拉斯加,平均每平方英里僅有一名居民。
這種數(shù)據(jù)合并操作在使用真實(shí)世界數(shù)據(jù)源回答問題時(shí)非常常見。
希望這個(gè)例子能讓你了解如何結(jié)合我們介紹過的工具,從數(shù)據(jù)中獲得洞見!
到此這篇關(guān)于Pandas 合并數(shù)據(jù)集merge 和 join的使用的文章就介紹到這了,更多相關(guān)Pandas 合并數(shù)據(jù)集內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python使用subprocess模塊輕松調(diào)用外部程序與命令
subprocess是Python的標(biāo)準(zhǔn)庫,它的設(shè)計(jì)目標(biāo)是替代舊有的os.system、os.popen等模塊,提供更統(tǒng)一、更強(qiáng)大的子進(jìn)程管理功能,所以本文給大家介紹了Python如何使用subprocess模塊輕松調(diào)用外部程序與命令,需要的朋友可以參考下2026-04-04
Python數(shù)據(jù)挖掘中常用的五種AutoEDA 工具總結(jié)
大家好,我們都知道在數(shù)據(jù)挖掘的過程中,數(shù)據(jù)探索性分析一直是非常耗時(shí)的一個(gè)環(huán)節(jié),但也是繞不開的一個(gè)環(huán)節(jié),本篇文章帶你盤點(diǎn)數(shù)據(jù)挖掘中常見的5種 AutoEDA 工具2021-11-11
Python實(shí)現(xiàn)8個(gè)概率分布公式的方法詳解
在本文中,我們將介紹一些常見的分布(均勻分布、高斯分布、對(duì)數(shù)正態(tài)分布等)并通過Python代碼進(jìn)行可視化以直觀地顯示它們,感興趣的可以學(xué)習(xí)一下2022-05-05
Python configparser模塊配置文件解析與應(yīng)用探究
在Python中,configparser模塊是用于處理配置文件的重要工具,本文將全面探討configparser模塊的使用方法,包括讀取、修改、寫入配置文件,以及如何在實(shí)際項(xiàng)目中應(yīng)用該模塊,結(jié)合豐富的示例代碼,將深入剖析該模塊的功能和靈活性2024-01-01
Python 統(tǒng)計(jì)字?jǐn)?shù)的思路詳解
這篇文章主要介紹了Python 統(tǒng)計(jì)字?jǐn)?shù)的思路詳解,文中還給大家提供了不借助第三方模塊的解決方法,感興趣的朋友一起看看吧2018-05-05
Python解析json文件相關(guān)知識(shí)學(xué)習(xí)
JSON(JavaScript Object Notation) 是一種輕量級(jí)的數(shù)據(jù)交換格式。接下來通過本文給大家介紹python解析json文件相關(guān)知識(shí),對(duì)python解析json文件相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2016-03-03
Python學(xué)習(xí)筆記之os模塊使用總結(jié)
這篇文章主要介紹了Python學(xué)習(xí)筆記之os模塊使用總結(jié),本文總結(jié)了多個(gè)常用方法,需要的朋友可以參考下2014-11-11

