pandas 进阶 --- 去重 合并 与实战

1.去重

1.1 groupby

groupby用于对pandas数据进行分组,使用示例如下:

card_group=card_df.groupby(['id','how'])['amount'].sum()

首先我们根据id和how两列对数据进行分组,并对分组结果中的amount列进行求和运算,返回最后的结果。

1.2 pivot_table

pivot_table是pandas提供的透视表函数,它根据一个或多个键对数据进行聚合,并根据行列上的分组键将数据分配到各个矩形区域中。使用示例如下:

card_df.pivot_table('amount',index=['id'],columns=['how'],aggfunc=sum)

这里,我们指定行索引为id列,列索引为how列,并返回amount列按照aggfunc参数指定的聚合方法的聚合结果值,这样描述起来可能有些拗口,举个简单的例子,比如原使数据是下面这个样子:

id  how   amount
01  食堂    200
01  淋浴    10
01  食堂    20
02  食堂    300
02  淋浴    50
02  淋浴    30
02  食堂    150

则按照上面的方式生成的透视表如下所示:

    食堂   淋浴
01  220    10
02  450    80

2 图书数据处理

这里,小编将介绍官方给出的图书馆数据的处理过程,首先回顾一下图书馆数据样例:

图书馆的开放时间为早上7点到晚上22点,门禁编号数据在2014/02/23之前只有“编号”信息,之后引入了“进门、出门”信息,还有些异常信息为null,请参赛者自行处理。 字段描述和示例如下: 学生id,门禁编号,具体时间 3684,"5","2013/09/01 08:42:50" 7434,"5","2013/09/01 08:50:08" 8000,"进门2","2014/03/31 18:20:31" 5332,"小门","2014/04/03 20:11:06" 7397,"出门4","2014/09/04 16:50:51"

根据官方给出的数据,我们想要得到每位同学去过图书馆的天数统计信息,结果如下:

id    times                    
0     13         
1      1     
10     3   
19    10     
20    13     
21     3     
22     9        
23     7        
28    32          
29    38

下面开始介绍小编的数据处理过程,首先是从读入数据,很简单,使用read_csv的方法读入数据并指定其columns列表:

library_df=pd.read_csv('library_train.txt',header=None)
library_df.columns=['id','gate','time_stamp']
print (library_df.head(10))

读入的数据示例如下:

      id    gate       time_stamp
0   3684    5  2013/09/01 08:42:50
1  14314    6  2013/09/01 08:42:59
2   5108    9  2013/09/01 08:43:32
3   5826    7  2013/09/01 08:44:06
4   7730    5  2013/09/01 08:44:25
5   6668    7  2013/09/01 08:47:24
6  11636    8  2013/09/01 08:48:24
7   4036    6  2013/09/01 08:49:53
8   4050    5  2013/09/01 08:50:01
9   7434    5  2013/09/01 08:50:08

我们可以注意到,time_stamp列记录的是每次进或出图书馆的具体时间,精确到了秒,那么如果想要得到在该段时间内每位同学去图书馆的天数统计,下面的两条数据其实只能算作一天:

扫描二维码关注公众号,回复: 1107195 查看本文章
           id  gate     time_stamp
14878    0    7  2013/10/15 14:55:48
14925    0    7  2013/10/15 18:04:36

这时候很自然的想到对数据进行去重,但是上面两条数据的time_stamp是不一样的呀,无法进行去重,但我们注意到二者在精确到天时数据是一样的,因此我们只需要截取其中的年月日信息,二者就会变成两条重复数据。我们使用pandas的str提供的方法,对字符串进行截取,代码如下:

library_df['time_stamp']=library_df['time_stamp'].str[:10]

在pandas中操作字符串是必须使用.str,其它用法举例如下:

data.str.split(';')
data.str.replace('a','b')

关于pandas中字符串的操作不是本文的重点,此处不再赘述。

经过对字符串的截取操作,我们得到了如下的数据:

           id  gate  time_stamp
14878    0    7  2013/10/15
14925    0    7  2013/10/15

接下来我们就可以进行数据去重了,使用pandas中的drop_duplicates()方法,示例如下:

library_df.drop_duplicates(['id','time_stamp'],keep='last',inplace=True)

可以看到我们指定了三个参数,第一个参数是根据哪几列进行去重的列表,这里我们指定了id和time_stamp两列,如果两条数据的这两列值相同,则会被当成重复列对待。第二个参数是keep参数,pandas默认在去重时是去掉所有重复数据,使用keep参数可以让我们保留重复数据中的一条而删掉其他的数据,keep='last'表明保留重复数据中的最后一条,当然你也可以使用keep='first'来保留第一条数据。最后一个参数时inplace参数,我们直接替换library_df的数据,而无需赋值给另一个新的DataFrame。

我们来看看此时id为0的同学的所有记录,代码如下:

print (library_df[library_df['id']==0])

输出结果如下:

           id  gate  time_stamp 
14925    0    7  2013/10/15   
15790    0    7  2013/10/17   
17394    0    6  2013/10/21   
17838    0    8  2013/10/22   
20000    0    6  2013/10/27   
23869    0    4  2013/11/04   
24550    0    5  2013/11/05   
33365    0    7  2013/11/20   
44954    0    5  2013/12/10   
49583    0    7  2013/12/17   
70052    0    5  2014/01/03   
79702    0    6  2014/01/09   
161664   0  进门1  2014/03/25 

可以看到,结果中已经不存在id和time_stamp均相同的数据了。

接下来的工作就简单了,按照上一节提到的groupby方法,按照id列进行分组聚合就可以了,代码如下:

library_count_df=library_df.groupby(['id'])['time_stamp'].count()

这里,我们按照id列进行分组,并对返回结果中的time_stamp列进行计数处理,最终结果如下:

id
0         13
1          1
10         3
19        10
20        13
21         3
22         9
23         7
28        32
29        38

最后,使用to_csv方法写入到文件中即可。

library_count_df.to_csv('library.csv',encoding='gbk')

3 合并

首先,小编带你回顾一下drop_duplicates()方法的使用,我们定义一个DataFrame如下:

df=pd.DataFrame({'id':[1,1,2],'value':[5,10,12]})
print (df)

输出如下:

   id  value
0   1      5
1   1     10
2   2     12

可以看到,有两个id为1的数据行,如果我们只想保留最后一条id为1的数据,那么使用drop_duplicates()方法如下:

df.drop_duplicates(['id'],keep='last',inplace=True)
print (df)

得到如下的结果:

   id  value
1   1     10
2   2     12

2 使用pandas合并数据

根据官方给出的数据,我们分别提取了消费数据、图书馆进出数据、图书借阅数据的特征,并分别写入了不同的csv文件。那么我们如何将这一系列数据文件合并成一个文件呢?pandas提供了多种对数据进行合并的方法,不过本文主要介绍的是merge()方法的应用。

由于官方数据比较复杂,我们将使用两个简单的DataFrame来介绍merge函数的应用:

df1=pd.DataFrame({'key':['b','b','a','c','a','a','b'],
                  'data':range(7)})
df2=pd.DataFrame({'key':['a','b','d'],
                  'data2':range(3)})

输出两个表:

   data key
0     0   b
1     1   b
2     2   a
3     3   c
4     4   a
5     5   a
6     6   b
   data2 key
0      0   a
1      1   b
2      2   d

首先我们来看看直接使用merge()方法的效果:

   data key  data2
0     0   b      1
1     1   b      1
2     6   b      1
3     2   a      0
4     4   a      0
5     5   a      0

可以看到,我们在合并数据表时并没有指定根据哪一列合并,那么pandas会自动搜索两个DataFrame中的相同列,如果有,则按该列进行合并,如果没有,则会报下面的错:

pandas.tools.merge.MergeError: No common columns to perform merge on

好了,了解了merge的基本使用,我们接下来主要来探究两个问题:

2.1 关于连接属性

在上面的合并过程中,我们并没有指定合并的列,它会自动搜索两个DataFrame中相同的列进行合并,所以上述代码与下面的代码效果是一样的:

(pd.merge(df1,df2,on='key'))

如果两个数据表中没有相同的列呢?假定我们的两个数据表是下面的样子:

df3=pd.DataFrame({'key1':['b','b','a','c','a','a','b'],
                  'data':range(7)})
df4=pd.DataFrame({'key2':['a','b','d'],
                  'data2':range(3)})

此时,我们需要显式地指定根据哪一列进行合并,代码如下:

print (pd.merge(df3,df4,left_on='key1',right_on='key2'))

输出如下:

   data key1  data2 key2
0     0    b      1    b
1     1    b      1    b
2     6    b      1    b
3     2    a      0    a
4     4    a      0    a
5     5    a      0    a

可以看到,我们指定按照df3的key1列和df4的key2列进行合并,结果中两列的值都是相同的。

2.2 关于连接方式

细心的读者可能已经发现了,在我们合并df1和df2的时候,我们没有指定按照何种方式连接,结果中没有key值为‘c’或者‘d’的数据,这是因为pandas的merge()方法默认使用的是内连接(inner),结果中的键是交集,即只有key值为‘a'和’b'的列,因此上述合并df1和df2的代码和下面的代码等同:

pd.merge(df1,df2,how='inner')

另一个需要注意的地方是,pandas对相同的键做笛卡尔积运算。例如df1中key值为’a'的有3行,df2种key值为‘a’的有1行,那么合并结果中key值为‘a’的有3*1=3行。

如果不想做内连接,pandas提供了像数据库一样的外连接方式,有全外连接、左外连接和右外连接三种方式,接下来,小编带你探究这三种方式的区别:

全外连接

使用如下的代码进行全外连接

print (pd.merge(df1,df2,how='outer'))

输出如下:

   data key  data2
0   0.0   b    1.0
1   1.0   b    1.0
2   6.0   b    1.0
3   2.0   a    0.0
4   4.0   a    0.0
5   5.0   a    0.0
6   3.0   c    NaN
7   NaN   d    2.0

可以看到,全外连接取的是两个DataFrame的键的并集,如果一个键只在其中一个DataFrame中出现,则结果中会用NaN来补足数据。例如,只有df1中有key值为‘c’的数据,则合并结果中data2列使用NaN来补足数据。

左外连接

使用如下的代码进行左外连接

print (pd.merge(df1,df2,how='left'))

输出如下:

   data key  data2
0   0.0   b    1.0
1   1.0   b    1.0
2   6.0   b    1.0
3   2.0   a    0.0
4   4.0   a    0.0
5   5.0   a    0.0
6   3.0   c    NaN

可以看到,左外连接求取的是左边DataFrame即df1的键值,即['a','b','c'],那么如果某些键不存在于右边的DataFrame中,对应的数据以NaN补足。

右外连接

使用如下的代码进行右外连接

print (pd.merge(df1,df2,how='right'))

输出如下:

   data key  data2
0   0.0   b    1.0
1   1.0   b    1.0
2   6.0   b    1.0
3   2.0   a    0.0
4   4.0   a    0.0
5   5.0   a    0.0
6   NaN   d    2.0

可以看到,右外连接求取的是右边DataFrame即df2的键值,即['a','b','d'],那么如果某些键不存在于左边的DataFrame中,对应的数据以NaN补足。

3 总结

本篇,小编带你初步探索了pandas中合并数据表方法merge()的应用,并重点介绍了两个主要的参数,连接键值on和连接方式how。至此,有关数据特征提取以及数据合并的工作已经全部结束,下一节,小编将要开始带领大家一起使用sklearn机器学习包对数据进行分类预测,敬请期待!

本文,小编主要介绍了对官方给出的图书馆数据的处理过程,图书馆借阅数据的处理过程类似,同样得到每位同学的借书数量。这里主要运用了groupby()对数据进行分组,以及运用drop_duplicates()去除重复数据。现在,所有的数据都已经初步处理完毕,接下来需要对数据进行归总。那么,下一篇,小编将带你探索利用pandas合并数据的奥秘,敬请期待!

猜你喜欢

转载自blog.csdn.net/weixin_40907382/article/details/79919253