数据手拉手
我们经常要从多个渠道获得数据来综合进行分析。例如需要处理几十个甚至更多的数据文件,这需要我们把多个数据源的数据合并在一起。
这里我们需要学习如何利用pandas整合多个DataFrame或者Series中的数据。
数据源介绍
数据源是国家统计局的全国35个主要城市2000年到2017年的理念房价数据。
import pandas as pd
df=pd.read_csv('city_house_price.csv')
df.head(10)
城市 | 2017年 | 2016年 | 2015年 | 2014年 | 2013年 | 2012年 | 2011年 | 2010年 | 2009年 | 2008年 | 2007年 | 2006年 | 2005年 | 2004年 | 2003年 | 2002年 | 2001年 | 2000年 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 北京 | 34117 | 28489 | 22300 | 18499 | 17854 | 16553.48 | 15517.90 | 17151 | 13224 | 11648 | 10661.24 | 7375.41 | 6162.13 | 4747.14 | 4456 | 4467 | 4716.0 | 4557.0 |
1 | 天津 | 15139 | 12870 | 9931 | 8828 | 8390 | 8009.58 | 8547.64 | 7940 | 6605 | 5598 | 5575.72 | 4649.25 | 3987.22 | 2950.34 | 2393 | 2414 | 2308.0 | 2274.0 |
2 | 石家庄 | 9738 | 7354 | 7798 | 5562 | 4943 | 4713.54 | 4352.15 | 3807 | 3688 | 2630 | 2378.11 | 2005.13 | 1705.23 | 1533.78 | 1570 | 1555 | NaN | NaN |
3 | 太原 | 8827 | 7348 | 7303 | 7155 | 6668 | 6404.74 | 6517.47 | 7088 | 4499 | 3743 | 3560.54 | 3156.26 | 2902.66 | 2332.60 | 2204 | 1899 | NaN | NaN |
4 | 呼和浩特 | 5662 | 5196 | 4946 | 5153 | 4631 | 4798.17 | 4073.32 | 3650 | 3248 | 2511 | 2458.82 | 2175.71 | 1540.78 | 1430.16 | 1277 | 1202 | NaN | NaN |
5 | 沈阳 | 7944 | 6838 | 6416 | 5865 | 6074 | 5989.45 | 5612.96 | 5109 | 4196 | 3856 | 3535.75 | 3184.00 | 3026.64 | 2851.72 | 2753 | 2601 | NaN | NaN |
6 | 大连 | 10019 | 9119 | 8711 | 8921 | 7859 | 7583.97 | 7928.98 | 6759 | 6175 | 5617 | 5417.28 | 4256.42 | 3579.86 | 2972.74 | 2699 | 2668 | NaN | NaN |
7 | 长春 | 6811 | 6018 | 6374 | 5847 | 5729 | 5273.35 | 5969.66 | 5097 | 4012 | 3344 | 3118.30 | 2408.03 | 2271.70 | 2118.97 | 1973 | 2064 | NaN | NaN |
8 | 哈尔滨 | 7861 | 6338 | 6124 | 5751 | 5884 | 5112.85 | 5216.66 | 5196 | 4146 | 3515 | 2942.74 | 2502.86 | 2384.04 | 2215.19 | 2183 | 2157 | NaN | NaN |
9 | 上海 | 24866 | 25910 | 21501 | 16415 | 16192 | 13869.88 | 13565.83 | 14290 | 12364 | 8115 | 8253.00 | 7039.00 | 6698.00 | 5761.21 | 4989 | 4007 | 3658.0 | 3326.0 |
df.shape
(35, 19)
concat
concat 解决的是对数据进行合并的问题
例如,现在有3张表格分别存储了1月1号、1月2号和1月3号的订单信息,3张表格包含的列信息完全一致。这个时候我们可以按行对数据进行合并,用一张表格吧3天的数据合并在一起
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZCON3ShX-1586261815356)(./1.gif)]
或者是有另外两张表格,分别存储每个城市本周每天的销售金额和上周每天的销售金额。那我么可以对数据按列进行合并,得到每个城市本周和上周每天的销售金额的数据。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uvw2pI9E-1586261815358)(./2.gif)]
这两种情况,我们都可以利用concat()方法对数据进行合并。先看一下concat()方法的格式。
pd.concat(objs, axis=0, join='outer', ignore_index=False,
keys=None, levels=None, names=None, verify_integrity=False,
copy=True)
objs:列表对象,待合并的DataFrame或者Series,可以包含两个或者两个以上的对象。
axis:用来指定按行(上下拼)还是按列(左右拼)合并,默认按照行进行合并。如果需要按照列进行合并,需要指定参数axis=1
join:确定合并时候记录的匹配方法,后面介绍按列合并的时候会专门展开。
按行进行合并
下面的例子里,我们以文件里读出的原始数据作为基础,生成两个新的DataFrame,然后生成两个新的DataFrame,然后按照行来进行合并。
import pandas as pd
df=pd.read_csv('city_house_price.csv',index_col='城市')
df1=df[0:5]
df2=df[5:10]
df3=pd.concat([df1,df2])
df3
2017年 | 2016年 | 2015年 | 2014年 | 2013年 | 2012年 | 2011年 | 2010年 | 2009年 | 2008年 | 2007年 | 2006年 | 2005年 | 2004年 | 2003年 | 2002年 | 2001年 | 2000年 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
城市 | ||||||||||||||||||
北京 | 34117 | 28489 | 22300 | 18499 | 17854 | 16553.48 | 15517.90 | 17151 | 13224 | 11648 | 10661.24 | 7375.41 | 6162.13 | 4747.14 | 4456 | 4467 | 4716.0 | 4557.0 |
天津 | 15139 | 12870 | 9931 | 8828 | 8390 | 8009.58 | 8547.64 | 7940 | 6605 | 5598 | 5575.72 | 4649.25 | 3987.22 | 2950.34 | 2393 | 2414 | 2308.0 | 2274.0 |
石家庄 | 9738 | 7354 | 7798 | 5562 | 4943 | 4713.54 | 4352.15 | 3807 | 3688 | 2630 | 2378.11 | 2005.13 | 1705.23 | 1533.78 | 1570 | 1555 | NaN | NaN |
太原 | 8827 | 7348 | 7303 | 7155 | 6668 | 6404.74 | 6517.47 | 7088 | 4499 | 3743 | 3560.54 | 3156.26 | 2902.66 | 2332.60 | 2204 | 1899 | NaN | NaN |
呼和浩特 | 5662 | 5196 | 4946 | 5153 | 4631 | 4798.17 | 4073.32 | 3650 | 3248 | 2511 | 2458.82 | 2175.71 | 1540.78 | 1430.16 | 1277 | 1202 | NaN | NaN |
沈阳 | 7944 | 6838 | 6416 | 5865 | 6074 | 5989.45 | 5612.96 | 5109 | 4196 | 3856 | 3535.75 | 3184.00 | 3026.64 | 2851.72 | 2753 | 2601 | NaN | NaN |
大连 | 10019 | 9119 | 8711 | 8921 | 7859 | 7583.97 | 7928.98 | 6759 | 6175 | 5617 | 5417.28 | 4256.42 | 3579.86 | 2972.74 | 2699 | 2668 | NaN | NaN |
长春 | 6811 | 6018 | 6374 | 5847 | 5729 | 5273.35 | 5969.66 | 5097 | 4012 | 3344 | 3118.30 | 2408.03 | 2271.70 | 2118.97 | 1973 | 2064 | NaN | NaN |
哈尔滨 | 7861 | 6338 | 6124 | 5751 | 5884 | 5112.85 | 5216.66 | 5196 | 4146 | 3515 | 2942.74 | 2502.86 | 2384.04 | 2215.19 | 2183 | 2157 | NaN | NaN |
上海 | 24866 | 25910 | 21501 | 16415 | 16192 | 13869.88 | 13565.83 | 14290 | 12364 | 8115 | 8253.00 | 7039.00 | 6698.00 | 5761.21 | 4989 | 4007 | 3658.0 | 3326.0 |
按列进行合并
concat()默认按照行进行合并,我们可以通过设定参数axis=1把多个DataFrame按照列来进行合并。
import pandas as pd
df=pd.read_csv('city_house_price.csv',index_col='城市')
df1=df.loc[:,['2017年','2016年','2015年']]
df2=df.loc[:,['2014年','2013年','2012年']]
df3=pd.concat([df1,df2],axis=1)
df3.head
<bound method NDFrame.head of 2017年 2016年 2015年 2014年 2013年 2012年
城市
北京 34117 28489 22300 18499 17854 16553.48
天津 15139 12870 9931 8828 8390 8009.58
石家庄 9738 7354 7798 5562 4943 4713.54
太原 8827 7348 7303 7155 6668 6404.74
呼和浩特 5662 5196 4946 5153 4631 4798.17
沈阳 7944 6838 6416 5865 6074 5989.45
大连 10019 9119 8711 8921 7859 7583.97
长春 6811 6018 6374 5847 5729 5273.35
哈尔滨 7861 6338 6124 5751 5884 5112.85
上海 24866 25910 21501 16415 16192 13869.88
南京 15259 17884 11260 10964 11078 9674.84
杭州 21225 16211 14748 14035 14679 13291.65
宁波 14145 11738 11022 10890 11405 11385.25
合肥 11442 9312 7512 6917 6084 5754.31
福州 10547 11058 11333 10105 10155 10644.52
厦门 28053 25251 18928 17778 14551 12953.38
南昌 8106 7707 6955 6225 6639 5879.99
济南 9712 8405 7527 7158 7013 6650.56
青岛 10052 8997 8437 7855 7987 7583.36
郑州 8323 8093 7223 6579 6587 5643.07
武汉 11453 9819 8404 7399 7238 6895.35
长沙 7287 6160 5544 5458 5759 5602.51
广州 17685 16346 14083 14739 13954 12000.88
深圳 48622 45498 33661 24040 23427 18995.92
南宁 7700 6767 6229 6103 6155 5618.65
海口 11694 8868 7636 7473 7342 6512.03
重庆 6605 5162 5012 5094 5239 4804.80
成都 8595 7377 6584 6536 6708 6678.46
贵阳 6552 5392 4967 4904 4488 4472.69
昆明 8197 6851 7178 6067 5615 5404.90
西安 8166 6385 6221 6105 6435 6224.03
兰州 7137 6162 6089 5860 5520 5420.67
西宁 5890 5007 4602 4807 4380 4304.29
银川 4892 4448 4498 4111 4524 4187.26
乌鲁木齐 6188 5829 6142 5758 5858 5255.04>
索引值的匹配方式
上面在按列对数据进行合并的时候,df1和df2行索引都是城市名称,因为在文件中读取数据的时候,指定了参数index_col为城市,不存在匹配不了的情况。如果两个DataFrame的行索引值不一样,我们如何处理呢?
现在我们来认为的创造两个DataFrame,让它们包含的行索引值不完全一致,看默认情况下pandas如何进行处理。
import pandas as pd
df=pd.read_csv('city_house_price.csv',index_col='城市')
df1=df[['2017年','2016年']].loc[['北京','上海']]
df2=df[['2007年','2006年']].loc[['北京','深圳']]
#按列进行合并
df4=pd.concat([df1,df2],axis=1)
df4
2017年 | 2016年 | 2007年 | 2006年 | |
---|---|---|---|---|
北京 | 34117.0 | 28489.0 | 10661.24 | 7375.41 |
上海 | 24866.0 | 25910.0 | NaN | NaN |
深圳 | NaN | NaN | 13369.63 | 8848.04 |
这段代码,我们通过读取的文件分别构造了两个DataFrame,以城市字段作为结果的行索引。df1包含了北京和上海两个城市2017和2016年的房价数据,df2包括了北京和深圳两个城市2006和2007年的数据,只有北京这个城市的数据在两个DataFrame中都存在。
合并以后,结果一共包括3条记录。北京这一行合并了df1和df2中的数据,其它城市数据不全的用NaN进行了填充。
这是默认情况下pandas列合并的处理方式,取2个DataFrame行索引的并集,缺失的数据会用空值进行填充。
我们也可以要求pandas在合并时取原始数据行索引的交集,就是行索引同时存在df1和df2中的那些数据会在结果中保留下来。调用concat方法的时候设定join=‘inner’ 就可以实现。
import pandas as pd
df=pd.read_csv('city_house_price.csv',index_col='城市')
df1=df[['2017年','2016年']].loc[['北京','上海']]
df2=df[['2007年','2006年']].loc[['北京','深圳']]
#按列进行合并
df4=pd.concat([df1,df2],axis=1,join='inner')
df4
2017年 | 2016年 | 2007年 | 2006年 | |
---|---|---|---|---|
城市 | ||||
北京 | 34117 | 28489 | 10661.24 | 7375.41 |
通过程序的运行结果我们看到,合并后的DataFrame只包含了北京这个城市的数据。
除了交集或者并集,我们还可以指定合并后的结果行索引是参与合并的某一个数据的行索引。
比如我们希望取df2的行索引作为合并结果中的索引,我们可以使用DataFrame的reindex()方法,将每个参与concat()操作的DataFrame的行索引都指定为df2的行索引。
import pandas as pd
df=pd.read_csv('city_house_price.csv',index_col='城市')
#准备待合并数据
df1=df[['2017年','2016年']].loc[['北京','上海']]
df2=df[['2007年','2006年']].loc[['北京','深圳','杭州']]
s1=df['2010年'].loc[['北京','深圳','长沙']]
#合并3组数据,以df2行索引值为准
df6=pd.concat([df1.reindex(df2.index),df2,s1.reindex(df2.index)],axis=1)
df6
2017年 | 2016年 | 2007年 | 2006年 | 2010年 | |
---|---|---|---|---|---|
城市 | |||||
北京 | 34117.0 | 28489.0 | 10661.24 | 7375.41 | 17151.0 |
深圳 | NaN | NaN | 13369.63 | 8848.04 | 18954.0 |
杭州 | NaN | NaN | 7431.76 | 5967.44 | NaN |
从程序的运行结果中我们看到,合并后的结果包含了北京、深圳、杭州这3个城市的数据,直接使用了df2这个DataFrame的行索引作为结果的行索引。
上面代码中我们还做了些新的尝试,比如,以供有3个数据参与合并,合并的数据中,s1是Series类型的。这是为了向你展示:
1.concat时参与合并的变量没有数目的限制。
2.DataFrame和Series可以一起参与合并。
merge
concat可以很方便的解决合并的问题。除此之外,有另外一种相对复杂的情况。
看一个具体的例子。我们现在有2份数据,第1份数据存储的是订单信息,包含订单号、用户姓名、订单金额等。
第二份数据存储的是用户信息,包括用户姓名、电话号码、地址、用户注册时间等信息。
现在有这样的需求,希望通过订单信息里的用户姓名,在用户信息里获得用户的电话号码、注册时间等信息。
这就是merge可以解决的问题。下面我们来认识一下merge函数和它的参数,对参数具体的使用,在后面会结合案例进行演示和介绍。
pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
left_index=False, right_index=False, sort=True,
suffixes=('_x', '_y'), copy=True, indicator=False,
validate=None
```
left,right:用于连接的2个DataFrame,用左右来区分。注意merge函数一次只能连接2张表,如果需要连接多张表,可以连续使用多次merge函数。
on: 当两个DataFrame提供的合并列的列名称相同时,只设置on为合并列的列名称就可以。
left_on,right_on:当左右两个DataFrame提供的合并列的列名称不同时,适合使用这两个参数。
<table><tr><td bgcolor=yellow>how</td></tr></table>:连接的方式可以是外连接、内连接、左连接、右连接,默认使用内连接。具体的区别稍后会重点展开。
```python
import pandas as pd
df=pd.read_csv('city_province.csv')
df.head()
city | province | |
---|---|---|
0 | 北京 | 北京 |
1 | 天津 | 天津 |
2 | 石家庄 | 河北 |
3 | 太原 | 山西 |
4 | 呼和浩特 | 内蒙 |
df3=pd.merge(df1,df2,right_on='city',left_on='城市')
df3
import pandas as pd
df_price=pd.read_csv('city_house_price.csv')
df_province=pd.read_csv('city_province.csv')
df1=df_price.iloc[0:10,0:4]
df2=df_province.iloc[5:15]
df1
城市 | 2017年 | 2016年 | 2015年 | |
---|---|---|---|---|
0 | 北京 | 34117 | 28489 | 22300 |
1 | 天津 | 15139 | 12870 | 9931 |
2 | 石家庄 | 9738 | 7354 | 7798 |
3 | 太原 | 8827 | 7348 | 7303 |
4 | 呼和浩特 | 5662 | 5196 | 4946 |
5 | 沈阳 | 7944 | 6838 | 6416 |
6 | 大连 | 10019 | 9119 | 8711 |
7 | 长春 | 6811 | 6018 | 6374 |
8 | 哈尔滨 | 7861 | 6338 | 6124 |
9 | 上海 | 24866 | 25910 | 21501 |
df2
city | province | |
---|---|---|
5 | 沈阳 | 辽宁 |
6 | 大连 | 辽宁 |
7 | 长春 | 吉林 |
8 | 哈尔滨 | 黑龙江 |
9 | 上海 | 上海 |
10 | 南京 | 江苏 |
11 | 杭州 | 浙江 |
12 | 宁波 | 浙江 |
13 | 合肥 | 安徽 |
14 | 福州 | 福建 |
df3=pd.merge(df1,df2,right_on='city',left_on='城市')