pandas教程:Combining and Merging Datasets 合并数据集

news/2024/7/5 23:35:15 标签: pandas, word, python, r语言, windows, ppt

8.2 Combining and Merging Datasets(合并数据集)

pandas里有几种方法可以合并数据:

  1. pandas.merge 按一个或多个keyDataFrame中的行连接起来。这个和SQL或其他一些关系型数据库中的join操作相似。
  2. pandas.concat 在一个axis(轴)上,串联或堆叠(stack)多个对象。
  3. combine_first 实例方法(instance method)能拼接相互之间有重复的数据,并用一个对象里的值填满缺失值

这里每一个都会给出一些例子。这些用法贯穿这本书。

1 Database-Style DataFrame Joins(数据库风格的DataFrame Joins)

Mergejoin操作,能通过一个或多个key,把不同的数据集的行连接在一起。这种操作主要集中于关系型数据库。pandas中的merge函数是这种操作的主要切入点:

python">word">import pandas word">as pd
word">import numpy word">as np
python">df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
                    'data1': range(7)})

df1
data1key
00b
11b
22a
33c
44a
55a
66b
python">df2 = pd.DataFrame({'key': ['a', 'b', 'd'],
                    'data2': range(3)})
df2
data2key
00a
11b
22d

这个例子是many-to-one join(多个变为一个的结合);在df1中有标签为ab的行,而df2中的key列,每一行只有对应的一个值。调用merge我们可以得到:

python">pd.merge(df1, df2)
data1keydata2
00b1
11b1
26b1
32a0
44a0
55a0

这里我们并没有指定按哪一列来合并。如果我们没有指定,merge会用两个对象中都存在的列名作为key(键)。当然,最好还是清楚指定比较好:

python">pd.merge(df1, df2, on='key')
data1keydata2
00b1
11b1
26b1
32a0
44a0
55a0

如果每一个对象中的列名不一会,我们可以分别指定:

python">df3 = pd.DataFrame({'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 
                             'data1': range(7)})

df4 = pd.DataFrame({'rkey': ['a', 'b', 'd'], 
                             'data2': range(3)})
python">pd.merge(df3, df4, left_on='lkey', right_on='rkey')
data1lkeydata2rkey
00b1b
11b1b
26b1b
32a0a
44a0a
55a0a

我们可能注意到,在结果中并没有cd。因为merge默认是inner join(内联结),结果中的key是交集的结果,或者在两个表格中都有的集合。其他一些可选项,比如left, right, outer。outer join(外联结)取key的合集,其实就是left joinright join同时应用的效果:

python">pd.merge(df1, df2, how='outer')
data1keydata2
00.0b1.0
11.0b1.0
26.0b1.0
32.0a0.0
44.0a0.0
55.0a0.0
63.0cNaN
7NaNd2.0

many-to-many(多对多)结合也被定义好了,不过可能不是那么直观。这里有一个例子:

python">df1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'b'], 
                    'data1': range(6)})

df1
data1key
00b
11b
22a
33c
44a
55b
python">df2 = pd.DataFrame({'key': ['a', 'b', 'a', 'b', 'd'], 
                    'data2': range(5)})
df2
data2key
00a
11b
22a
33b
44d
python">pd.merge(df1, df2, on='key', how='left')
data1keydata2
00b1.0
10b3.0
21b1.0
31b3.0
42a0.0
52a2.0
63cNaN
74a0.0
84a2.0
95b1.0
105b3.0

many-to-many join是对行进行笛卡尔集运算。(两个集合X和Y的笛卡儿积(Cartesian product),又称直积,在集合论中表示为X × Y,是所有可能的有序对组成的集合。比如1到13是一个集合,四种花色是一个集合,二者的笛卡尔积就有52个元素)。这里在左侧的DataFrame中有三行含b,右边的DataFrame则有两行含b,于是结果是有六行含b。这个join方法只会让不相同的key值出现在最后的结果里:

python">pd.merge(df1, df2, how='inner')
data1keydata2
00b1
10b3
21b1
31b3
45b1
55b3
62a0
72a2
84a0
94a2

用多个key来联结的话,用一个含有多个列名的list来指定:

python">left = pd.DataFrame({'key1': ['foo', 'foo', 'bar'], 
                     'key2': ['one', 'two', 'one'], 
                     'lval': [1, 2, 3]})

right = pd.DataFrame({'key1': ['foo', 'foo', 'bar', 'bar'], 
                      'key2': ['one', 'one', 'one', 'two'], 
                      'rval': [4, 5, 6, 7]})
python">pd.merge(left, right, on=['key1', 'key2'], how='outer')
key1key2lvalrval
0fooone1.04.0
1fooone1.05.0
2footwo2.0NaN
3barone3.06.0
4bartwoNaN7.0

哪一种key组合会出现在结果里取决于merge方法的选择,可以把多个key当做一个tuple组成的单一key(尽管实际上并不是这样)。

注意:当我们讲列和列进行联结时,DataFrame中的index对象会被丢弃。

最后一个问题是在做merge操作的时候,如何处理重叠的列名。当我们想要手动去解决重叠问题时(参考重命名axis labels的部分),merge有一个suffixes选项,能让我们指定字符串,添加重叠的列名到左、右DataFrame

python">pd.merge(left, right, on='key1')
key1key2_xlvalkey2_yrval
0fooone1one4
1fooone1one5
2footwo2one4
3footwo2one5
4barone3one6
5barone3two7
python">pd.merge(left, right, on='key1', suffixes=('_left', '_right'))
key1key2_leftlvalkey2_rightrval
0fooone1one4
1fooone1one5
2footwo2one4
3footwo2one5
4barone3one6
5barone3two7

2 Merging on Index(在index上做合并)

在一些情况下,用于合并的key(键),可能是DataFrame中的index。这种情况下,可以使用left_index=Trueright_index=True来指明,哪一个index被用来作为合并键:

python">left1 = pd.DataFrame({'key': ['a', 'b', 'a', 'a', 'b', 'c'], 
                      'value': range(6)})

left1
keyvalue
0a0
1b1
2a2
3a3
4b4
5c5
python">right1 = pd.DataFrame({'group_val': [3.5, 7]}, index=['a', 'b'])
right1
group_val
a3.5
b7.0
python">pd.merge(left1, right1, left_on='key', right_index=True)
keyvaluegroup_val
0a03.5
2a23.5
3a33.5
1b17.0
4b47.0

merge的默认方法是用key的交集,我们也可以设定用合集,即outer join:

python">pd.merge(left1, right1, left_on='key', right_index=True, how='outer')
keyvaluegroup_val
0a03.5
2a23.5
3a33.5
1b17.0
4b47.0
5c5NaN

对于那些有多层级索引的数据,就更复杂了。index上的merge默认会是multiple-key merge(复数键合并):

python">lefth = pd.DataFrame({'key1': ['Ohio', 'Ohio', 'Ohio',
                               'Nevada', 'Nevada'], 
                      'key2': [2000, 2001, 2002, 2001, 2002], 
                      'data': np.arange(5.)})
lefth
datakey1key2
00.0Ohio2000
11.0Ohio2001
22.0Ohio2002
33.0Nevada2001
44.0Nevada2002
python">righth = pd.DataFrame(np.arange(12).reshape((6, 2)),
                      index=[['Nevada', 'Nevada', 'Ohio', 'Ohio', 
                              'Ohio', 'Ohio'], 
                             [2001, 2000, 2000, 2000, 2001, 2002]], 
                      columns=['event1', 'event2'])
righth
event1event2
Nevada200101
200023
Ohio200045
200067
200189
20021011

在这个例子里,我们必须指明将多列合并作为一个list(注意处理重复index的方法是令how='outer'):

python">pd.merge(lefth, righth, left_on=['key1', 'key2'], 
         right_index=True)
datakey1key2event1event2
00.0Ohio200045
00.0Ohio200067
11.0Ohio200189
22.0Ohio20021011
33.0Nevada200101
python">pd.merge(lefth, righth, left_on=['key1', 'key2'],
         right_index=True, how='outer')
datakey1key2event1event2
00.0Ohio2000.04.05.0
00.0Ohio2000.06.07.0
11.0Ohio2001.08.09.0
22.0Ohio2002.010.011.0
33.0Nevada2001.00.01.0
44.0Nevada2002.0NaNNaN
4NaNNevada2000.02.03.0

同时使用两个对象里的index来合并也是可能的:

python">left2 = pd.DataFrame([[1., 2.], [3., 4.], [5., 6.]], 
                     index=['a', 'c', 'e'], 
                     columns=['Ohio', 'Nevada'])

left2
OhioNevada
a1.02.0
c3.04.0
e5.06.0
python">right2 = pd.DataFrame([[7., 8.], [9., 10.], [11., 12.], [13, 14]], 
                      index=['b', 'c', 'd', 'e'],
                      columns=['Missouri', 'Alabama'])
right2
MissouriAlabama
b7.08.0
c9.010.0
d11.012.0
e13.014.0
python">pd.merge(left2, right2, how='outer', left_index=True, right_index=True)
OhioNevadaMissouriAlabama
a1.02.0NaNNaN
bNaNNaN7.08.0
c3.04.09.010.0
dNaNNaN11.012.0
e5.06.013.014.0

DataFrame有一个很便利的join实例,可以直接用index来合并。这个也可以用于与其他DataFrame进行合并,要有一样的index但不能由重叠的列:

python">left2.join(right2, how='outer')
OhioNevadaMissouriAlabama
a1.02.0NaNNaN
bNaNNaN7.08.0
c3.04.09.010.0
dNaNNaN11.012.0
e5.06.013.014.0

由于一些历史原因,在早期的pandas版本中,DataFramejoin方法是在结合键上做left join(左联结),这样会保留左侧Dataframe的行索引。这也支持把传入的dataframeindex与被调用的DataFramecolumn联结在一起:

python">left1.join(right1, on='key')
keyvaluegroup_val
0a03.5
1b17.0
2a23.5
3a33.5
4b47.0
5c5NaN

最后,对于简单的index-on-index合并,可以直接给join传入一个DataFrame。(作为备选,也可以使用最普遍的concat函数,这个在下一节会做介绍):

python">another = pd.DataFrame([[7., 8.], [9., 10.], [11., 12.], [16., 17.]], 
                       index=['a', 'c', 'e', 'f'], 
                       columns=['New York', 'Oregon'])
another
New YorkOregon
a7.08.0
c9.010.0
e11.012.0
f16.017.0
python">left2.join([right2, another])
OhioNevadaMissouriAlabamaNew YorkOregon
a1.02.0NaNNaN7.08.0
c3.04.09.010.09.010.0
e5.06.013.014.011.012.0
python">left2.join([right2, another], how='outer')
OhioNevadaMissouriAlabamaNew YorkOregon
a1.02.0NaNNaN7.08.0
bNaNNaN7.08.0NaNNaN
c3.04.09.010.09.010.0
dNaNNaN11.012.0NaNNaN
e5.06.013.014.011.012.0
fNaNNaNNaNNaN16.017.0

2 Concatenating Along an Axis(沿着轴连接)

另一种结合方式被称为可互换的,比如concatenation, binding, or stacking(连接,绑定,堆叠)。Numpy中的concatenate函数可以作用于numpy 数组:

python">arr = np.arange(12.).reshape((3, 4))
arr
array([[  0.,   1.,   2.,   3.],
       [  4.,   5.,   6.,   7.],
       [  8.,   9.,  10.,  11.]])
python">np.concatenate([arr, arr], axis=1)
array([[  0.,   1.,   2.,   3.,   0.,   1.,   2.,   3.],
       [  4.,   5.,   6.,   7.,   4.,   5.,   6.,   7.],
       [  8.,   9.,  10.,  11.,   8.,   9.,  10.,  11.]])

而在pandas的对象中,比如SeriesDataFrame,labeled axes(便签化的轴)能让我们做更泛化的数组连接操作。不过我们可能会有下面一些疑问:

  • 如果一个对象在其他轴上的index不同,我们应不应该在这些轴上把不同的元素连接起来,或者只用交集?

  • 经过连接操作后,连接的部分在输出对象里应不应该是可被识别的?

  • concatenation axis(连接轴)含有的数据需要被保留吗?在很多情况下,DataFrame中一些用整数做的label(标签)其实最好在连接后被删除。

pandas中的concat函数能解决上面这些问题。这里会给出几个例子来说明。假设我们有三个Series,他们指明没有index overlap(索引重叠):

python">s1 = pd.Series([0, 1], index=['a', 'b'])

s2 = pd.Series([2, 3, 4], index=['c', 'd', 'e'])

s3 = pd.Series([5, 6], index=['f', 'g'])

调用concat,把上面的series放在一个list里,结果会把值和索引都整合在一起:

python">pd.concat([s1, s2, s3])
a    0
b    1
c    2
d    3
e    4
f    5
g    6
dtype: int64

默认情况下,concataxis=0,结果会得到一个新的而series。如果令axis=1, 结果会变成一个DataFrameaxis=1 是列):

python">pd.concat([s1, s2, s3], axis=1)
012
a0.0NaNNaN
b1.0NaNNaN
cNaN2.0NaN
dNaN3.0NaN
eNaN4.0NaN
fNaNNaN5.0
gNaNNaN6.0

这种情况下,不会与其他轴产生重叠,效果与join中的outer join一样。你也可以通过设定join='inner'来使用交集:

python">s4 = pd.concat([s1, s3])
s4
a    0
b    1
f    5
g    6
dtype: int64
python">pd.concat([s1, s4], axis=1)
01
a0.00
b1.01
fNaN5
gNaN6
python">pd.concat([s1, s4], axis=1, join='inner')
01
a00
b11

因为join='inner',所以f和g标签消失了。

你也可以在join_axes中指定使用哪些轴:

python">pd.concat([s1, s4], axis=1, join_axes=[['a', 'c', 'b', 'e']])
01
a0.00.0
cNaNNaN
b1.01.0
eNaNNaN

一个潜在的问题是连接的部分在结果里是不可辨识的。假设我们想在连接轴上创建一个多层级索引,我们需要用到keys参数:

python">result = pd.concat([s1, s1, s3], keys=['one', 'two', 'three'])
result
one    a    0
       b    1
two    a    0
       b    1
three  f    5
       g    6
dtype: int64
python">result.unstack()
abfg
one0.01.0NaNNaN
two0.01.0NaNNaN
threeNaNNaN5.06.0

如果是设定axis=1,那么keys会变为DataFramecolumn header(列头):

python">word">print(s1)
word">print(s2)
word">print(s3)
a    0
b    1
dtype: int64
c    2
d    3
e    4
dtype: int64
f    5
g    6
dtype: int64
python">pd.concat([s1, s2, s3], axis=1, keys=['one', 'two', 'three'])
onetwothree
a0.0NaNNaN
b1.0NaNNaN
cNaN2.0NaN
dNaN3.0NaN
eNaN4.0NaN
fNaNNaN5.0
gNaNNaN6.0

这种逻辑也可以扩展到DataFrame对象上:

python">df1 = pd.DataFrame(np.arange(6).reshape(3, 2), index=['a', 'b', 'c'], 
                   columns=['one', 'two'])

df1
onetwo
a01
b23
c45
python">df2 = pd.DataFrame(5 + np.arange(4).reshape(2, 2), index=['a', 'c'], 
                   columns=['three', 'four'])
df2
threefour
a56
c78
python">pd.concat([df1, df2], axis=1, keys=['level1', 'level2'])
level1level2
onetwothreefour
a015.06.0
b23NaNNaN
c457.08.0

如果导入一个dict而不是list,那么dictkey会被用于上面concat中的keys选项:

python">pd.concat({'level1': df1, 'level2': df2}, axis=1)
level1level2
onetwothreefour
a015.06.0
b23NaNNaN
c457.08.0

还有其他一些选项负责多层级索引的设定(表8-3)。比如,可以给创建的axis level(轴层级)用names参数来命名:

python">pd.concat([df1, df2], axis=1, keys=['level1', 'level2'],
          names=['upper', 'lower'])
upperlevel1level2
loweronetwothreefour
a015.06.0
b23NaNNaN
c457.08.0

最后我们关心的是,在DataFrame中,行索引(row index)没有包含相关的数据:

python">df1 = pd.DataFrame(np.random.randn(3, 4), columns=['a', 'b', 'c', 'd'])
df1
abcd
01.049308-0.6607461.152071-1.447441
1-0.484170-0.096755-0.8153491.839818
2-0.2775410.164721-0.0124810.477152
python">df2 = pd.DataFrame(np.random.randn(2, 3), columns=['b', 'd', 'a'])
df2
bda
0-0.556378-2.286601-0.494776
11.1527160.270165-0.222289

这种情况下,可以设置ignore_index=True:

python">pd.concat([df1, df2], ignore_index=True)
abcd
01.049308-0.6607461.152071-1.447441
1-0.484170-0.096755-0.8153491.839818
2-0.2775410.164721-0.0124810.477152
3-0.494776-0.556378NaN-2.286601
4-0.2222891.152716NaN0.270165

3 Combining Data with Overlap

另一种数据结合方法既不属于merge,也不属于concatenation。比如两个数据集,index可能完全覆盖,或覆盖一部分。这里举个例子,考虑下numpywhere函数,可以在数组上进行类似于if-else表达式般的判断:

python">a = pd.Series([np.nan, 2.5, np.nan, 3.5, 4.5, np.nan], 
              index=['f', 'e', 'd', 'c', 'b', 'a'])

a
f    NaN
e    2.5
d    NaN
c    3.5
b    4.5
a    NaN
dtype: float64
python">b = pd.Series(np.arange(len(a), dtype=np.float64), 
              index=['f', 'e', 'd', 'c', 'b', 'a'])
b
f    0.0
e    1.0
d    2.0
c    3.0
b    4.0
a    5.0
dtype: float64
python">np.where(pd.isnull(a), b, a)
array([ 0. ,  2.5,  2. ,  3.5,  4.5,  5. ])

Series有一个combine_first方法,效果和上面是一样,而且还会自动对齐(比如把index按字母进行排列):

python">b[:-2].combine_first(a[2:])
a    NaN
b    4.5
c    3.0
d    2.0
e    1.0
f    0.0
dtype: float64

对于DataFramecombine_first可以在列与列之间做到同样的事情,可以认为是用传递的对象,给调用对象中的缺失值打补丁:

python">df1 = pd.DataFrame({'a': [1., np.nan, 5., np.nan], 
                    'b': [np.nan, 2., np.nan, 6.], 
                    'c': range(2, 18, 4)})

df1
abc
01.0NaN2
1NaN2.06
25.0NaN10
3NaN6.014
python">df2 = pd.DataFrame({'a': [5., 4., np.nan, 3., 7.], 
                    'b': [np.nan, 3., 4., 6., 8.]})
df2
ab
05.0NaN
14.03.0
2NaN4.0
33.06.0
47.08.0
python">df1.combine_first(df2)
abc
01.0NaN2.0
14.02.06.0
25.04.010.0
33.06.014.0
47.08.0NaN

http://www.niftyadmin.cn/n/5159700.html

相关文章

找到【SVM】中最优的惩罚项系数C

因为本来SVM是想找到间隔最大的分割面,所以C越大,SVC会选择边际更小的,能够更好的分类所有训练点的决策边界,不过模型的训练时间也会越长。如果C的设定值较小,那SVC会尽量最大化边界,决策功能会更简单&…

vue 跨标签页的数据共享(即跨标签页通信)

跨标签页通信的常见方案 LocalStorage 或 SessionStorage BroadCast Channel Service Worker Shared Worker Window.postMessage() Cookies IndexedDB 什么是跨标签页通信? 指在同一个浏览器窗口中的多个标签页之间进行数据交流和信息传递的过程。通常情况…

uniApp获取当前位置经纬度

以下是使用uni.getLocation获取当前位置的示例代码: 调用uni.getLocation方法获取当前位置信息 uni.getLocation({type: wgs84, // 坐标类型,默认为wgs84,可选的值为gcj02和bd09llsuccess: res > {// 获取成功,经度和纬度在r…

【踩坑专栏】禁止kafka自带的日志

在测试kafka的时候&#xff0c;有很多kafka自带的debug和info日志&#xff0c;需要禁止掉。 方法[1]如下&#xff1a; 在resource文件夹下&#xff0c;新增一个logback.xml文件。 内容如下&#xff1a; <configuration scan"true" scanPeriod"10 seconds&q…

C //习题 6.7 输出“魔方阵”。所谓魔方阵是指这样的方阵,它的每一行、每一列和对角线之和均相等。

C程序设计 &#xff08;第四版&#xff09; 谭浩强 习题 6.7 习题 6.7 输出“魔方阵”。所谓魔方阵是指这样的方阵&#xff0c;它的每一行、每一列和对角线之和均相等。例如&#xff0c;三阶魔方阵位 8 1 6 3 5 7 4 9 2 \begin{aligned}8 \ \ \ \ 1 \ \ \ \ 6\\3 \ \ \ \ 5 \ …

【软考:系统集成项目管理】之 项目成本管理

1. 成本管理的过程 制订成本管理计划成本估算成本预算成本控制 2. 过程的输入、输出、工具与技术 过程输入工具与技术输出1. 制订成本管理计划1. 项目管理计划 2. 项目章程 3. 事业环境因素 4. 组织过程资产1. 专家判断 2. 分析技术 3. 会议1. 成本管理计划2. 成本估算1. 成…

基于日期、时间、经纬度下载MODIS数据并批处理

一、利用python基于日期、时间和经纬度批量下载MODIS数据 我想根据一些实测点下载对应时间和位置的MODIS数据&#xff08;5min一景的产品&#xff09;作为对比。 之前想了很多种方法&#xff0c;比如基于GEE什么的&#xff0c;但是我下载的MODIS产品在GEE上没有。 于是后来考…

设计模式 -- 策略模式(Strategy Pattern)

策略模式&#xff1a;一种行为型模式&#xff0c;这些设计模式特别关注对象之间的通信。在策略模式中&#xff0c;我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。 介绍 意图&#xff1a;定义一系列的算…