一文过pandas入门(结篇)——才疏学浅的莫笑天

本来是准备直接上实战的,后来想了想还是先把必要的东西讲完吧,要不然到时候实战很多东西会很懵,又要递归的去讲就很麻烦。

这篇文章就是pandas的最后一篇内容讲解了,三篇连到一块应该足够应对绝大多数的内容过了,实际上也把pandas的主要内容讲的差不多了,漂亮的结一个尾吧。

先来口头阐述一下分组的概念

分组与聚合

其实分组就是字面意思呀

比如如下数据:(代码导入数据)

import pandas as pd
file_path = './split_test.xlsx'
df = pd.read_excel(file_path,sheet_name='Sheet1')
df
part id name score
0 a 1 张三 10
1 a 2 李四 5
2 b 3 王五 10
3 b 4 smith 6
4 c 5 kear 7
5 c 6 clack 8

将,part为a的放到一块,part为b的放到一块,part为c的放到一块就是一个分组。这种操作在sql语句中以gruoupby执行,实际上在pandas中也是这个方法,如下:

df1 = df.groupby('part')

输出数据

df1
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000024543471490>

可以看到它是获取了一个dataframegroupby对象的。

# 尝试读取它的数据,这一步没有出错说明它是可以迭代的。
for line in df1:
    print(line)
('a',   part  id name  score
0    a   1   张三     10
1    a   2   李四      5)
('b',   part  id   name  score
2    b   3     王五     10
3    b   4  smith      6)
('c',   part  id   name  score
4    c   5   kear      7
5    c   6  clack      8)
# print([line for line in df1])
print(list(df1)[0])
('a',   part  id name  score
0    a   1   张三     10
1    a   2   李四      5)

第一次遍历可以看到一个元组内两个元素,尝试利用两个占位符去遍历它。

for part,ele in df1:
    print(part,ele)
a   part  id name  score
0    a   1   张三     10
1    a   2   李四      5
b   part  id   name  score
2    b   3     王五     10
3    b   4  smith      6
c   part  id   name  score
4    c   5   kear      7
5    c   6  clack      8
# 查看一个块的类型
type(ele)
pandas.core.frame.DataFrame

这说明,每一组的ele也就是元素,都是一个dataframe对象,那么它自然而然继承了dataframe的所有方法。自然也可以取出其中所有的元素。

前面给一个印象呀。接下来我们来具体说明方法

# 查看数据
df
part id name score
0 a 1 张三 10
1 a 2 李四 5
2 b 3 王五 10
3 b 4 smith 6
4 c 5 kear 7
5 c 6 clack 8
# 整体对某个键进行分组
df_group_obj = df.groupby('part')
# 查看数据,可以发现,是为一个对象,注意这个对象仅包含分组的中间数据
print(df_group_obj)
# 利用该对象的size属性可以查看对应的元素数量
print(df_group_obj.size())
# 该对象同样可以调用某些dataframe对象的方法,比如:
# 对分组每列求均值
print(df_group_obj.mean())
# 对分组每列求和
print(df_group_obj.sum())
# 取出分组每列的最大值
print(df_group_obj.max())
# 取出分组每列的最小值
print(df_group_obj.min())
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x00000245494B2520>
part
a    2
b    2
c    2
dtype: int64
       id  score
part            
a     1.5    7.5
b     3.5    8.0
c     5.5    7.5
      id  score
part           
a      3     15
b      7     16
c     11     15
      id  name  score
part                 
a      2    李四     10
b      4    王五     10
c      6  kear      8
      id   name  score
part                  
a      1     张三      5
b      3  smith      6
c      5  clack      7

还要注意以上操作都是去对分组进行操作的,所以如果分为三个组,那么结果应该是三条记录(也就是三行)

扫描二维码关注公众号,回复: 13337465 查看本文章

上述操作是对整个df对象进行分组,同样可以取出每一列进行分组。

也就是对一个series对象同样可以进行该运算

# 但这里要注意groupby中的参数一定要用df取出,否则会报错,其实不难想呀,因为df['part']本身就是一个series对象,将两个series对象拼接起来,就是一
# 个dataframe,因此这里才可以使用分组方法。
ser_group_by = df['score'].groupby(df['part'])
# 剩下的操作跟上述相同,就需要过多解释了。
print(ser_group_by.size())
print(ser_group_by.max())
print(ser_group_by.min())
part
a    2
b    2
c    2
Name: score, dtype: int64
part
a    10
b    10
c     8
Name: score, dtype: int64
part
a    5
b    6
c    7
Name: score, dtype: int64

同样,我们可以自定义分组,只需要,定义的序列元素数与记录数(行数)是一样的。

# 随机产生一个序列
import random
group = [random.randint(1,4) for i in range(6)]
# 分组
df_group = df.groupby(group)
# 查看数据
print(df_group)
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000002454927ABB0>
print(df_group.size())
1    3
3    2
4    1
dtype: int64
## 作为验证,可以打印序列看看
print(group)
[1, 4, 1, 1, 3, 3]

根据多个键进行分组,构成分层索引

df_group = df.groupby(['part', 'name'])
print(df_group.size())
part  name 
a     张三       1
      李四       1
b     smith    1
      王五       1
c     clack    1
      kear     1
dtype: int64

另外我们需要考虑分组产生的数据的性质,根据上面的数据来分析

  1. 它是一个独特的对象,一个中间数据,且仅包含数据,该数据可以进行任何对于series和dataframe对象的运算。
  2. 它的索引由我们规定。比如我们分组是采用的两个键为参数,那么如上所示,它包含两层索引。
  3. 这个对象支持我们使用pandas的某些方法进行运算,但不一定支持所有的方法,所以在实在无法处理的情况下,我们可以将该对象转化为常用的数据结构,比如,dict或者list。
  4. 该对象支持迭代操作。
# 转化为列表
list(df_group)
[(('a', '张三'),
    part  id name  score
  0    a   1   张三     10),
 (('a', '李四'),
    part  id name  score
  1    a   2   李四      5),
 (('b', 'smith'),
    part  id   name  score
  3    b   4  smith      6),
 (('b', '王五'),
    part  id name  score
  2    b   3   王五     10),
 (('c', 'clack'),
    part  id   name  score
  5    c   6  clack      8),
 (('c', 'kear'),
    part  id  name  score
  4    c   5  kear      7)]
# 转化为字典
dict(list(df_group))
{('a',
  '张三'):   part  id name  score
 0    a   1   张三     10,
 ('a',
  '李四'):   part  id name  score
 1    a   2   李四      5,
 ('b',
  'smith'):   part  id   name  score
 3    b   4  smith      6,
 ('b',
  '王五'):   part  id name  score
 2    b   3   王五     10,
 ('c',
  'clack'):   part  id   name  score
 5    c   6  clack      8,
 ('c',
  'kear'):   part  id  name  score
 4    c   5  kear      7}

聚合运算

其实,在我们前面所说的内容中,已经包含了聚合运算,说白了它就是对每个分组的几条记录进行运算,不论是max,min,mean,sum,size方法都属于聚合运算。

前面没说的有一个describe方法,这个方法在讲dataframe的时候,已经讲过了,而且其实前文明确说出了,对于分组对象来说,dataframe的方法基本都是适用的呀,所以就没有特别提出。

df_group.describe()
id score
count mean std min 25% 50% 75% max count mean std min 25% 50% 75% max
part name
a 张三 1.0 1.0 NaN 1.0 1.0 1.0 1.0 1.0 1.0 10.0 NaN 10.0 10.0 10.0 10.0 10.0
李四 1.0 2.0 NaN 2.0 2.0 2.0 2.0 2.0 1.0 5.0 NaN 5.0 5.0 5.0 5.0 5.0
b smith 1.0 4.0 NaN 4.0 4.0 4.0 4.0 4.0 1.0 6.0 NaN 6.0 6.0 6.0 6.0 6.0
王五 1.0 3.0 NaN 3.0 3.0 3.0 3.0 3.0 1.0 10.0 NaN 10.0 10.0 10.0 10.0 10.0
c clack 1.0 6.0 NaN 6.0 6.0 6.0 6.0 6.0 1.0 8.0 NaN 8.0 8.0 8.0 8.0 8.0
kear 1.0 5.0 NaN 5.0 5.0 5.0 5.0 5.0 1.0 7.0 NaN 7.0 7.0 7.0 7.0 7.0

重点要点出的方法,自定义聚合方法

def my_func(df):
    """
    """
    return df.max() - df.min()

df_group_obj.agg(my_func)

# 函数传参,如果我们的函数带有()的话,这说明我们传的是函数的返回值,而不是一个方法,所以进行函数传参的的时候是不能带有()的。
id score
part
a 1 5
b 1 4
c 1 1
type(df_group_obj.agg(my_func))
pandas.core.frame.DataFrame
# 通过type可以看到,聚合方法返回的也是dataframe呀,我们可以通过agg传入多个函数名,得到结果如下:
df_group_obj.agg(['sum',my_func])
id score
sum my_func sum my_func
part
a 3 1 15 5
b 7 1 16 4
c 11 1 15 1
# 它的可操作性非常强呀,包括我们可以直接改变列名。
df_group_obj.agg(['sum',('新的列名',my_func)],)
id score
sum 新的列名 sum 新的列名
part
a 3 1 15 5
b 7 1 16 4
c 11 1 15 1

这里停一下,如上算是一个分组聚合的基本内容,上面的东西吃透了,基本就过关。

下来我们来看相对与基础来说,算进阶的内容,上一个模拟实例

通过上面的方法包括前面的一二篇博客,显然我们是已经能做到excel上的很多功能操作了,但是pandas的强大远不止于此。它能体现出代替excel的趋势,其实是依靠在这个行业非常顶级的一些python数据分析师,包括我们所有人都是想办法往这些方向靠拢啊,作为学习代价呢,excel显然是比python低的,并不是有什么歧视呀,这应该算公知,从定义来看,excel作为一款成熟的软件,pandas作为一个编程语言的工具包,它更底层呀,而更底层的东西,要实现同样的功能往往更难呀,但是如果你熟练了,你能做的,也会比单用excel要强大很多。

import pandas as pd
import random as rd
import string
## 随机生成一系列成熟数据,并写入excel表格。

data = {
    
    
    'id':[i for i in range(30)],
    'name': [''.join([rd.choice(string.ascii_letters) for i in range(5)]) for i in range(30)], # 姓名是可重复的。
    'part': [rd.choice(['a','b','c','d']) for i in range(30)],
    'score': [rd.randint(60,100) for i in range(30)]
}
data = pd.DataFrame(data)
data
data.to_excel('fin_exam.xlsx', sheet_name='data_score')
id name part score
0 0 DrPYm a 69
1 1 JFOUg d 89
2 2 fDGRR a 94
3 3 QEaJz a 66
4 4 IQwCs a 89
5 5 QglNK a 98
6 6 YEHEx b 77
7 7 CThQU a 61
8 8 ypFKY a 67
9 9 YkzKn b 72
10 10 BgoYQ b 75
11 11 WLSAQ a 91
12 12 wvGtX c 87
13 13 wZigu a 64
14 14 CgNab d 69
15 15 OLwjx c 98
16 16 OhMaH d 75
17 17 wZXNp b 82
18 18 unlzR a 93
19 19 mHbyE b 69
20 20 VjgMR a 63
21 21 JkrpE c 89
22 22 QLetK a 84
23 23 MIcMu d 63
24 24 DYdgN c 63
25 25 rrjMV d 98
26 26 mzSvn c 75
27 27 BjWdT d 76
28 28 dEPBF d 88
29 29 lrsGq c 62

任务:取出每一组的前三人的成绩

# 分组
data_group = data.groupby('part')
# 查看数据数量
print(data_group.size())
# 自定义运算
def top_3(df):
    # ascending=False参数表示降序排序
    return df.sort_values(by='score', ascending=False)[:3]
# 结果  
data_group.apply(top_3)
part
a    12
b     5
c     6
d     7
dtype: int64
id name part score
part
a 5 5 QglNK a 98
2 2 fDGRR a 94
18 18 unlzR a 93
b 17 17 wZXNp b 82
6 6 YEHEx b 77
10 10 BgoYQ b 75
c 15 15 OLwjx c 98
21 21 JkrpE c 89
12 12 wvGtX c 87
d 25 25 rrjMV d 98
1 1 JFOUg d 89
28 28 dEPBF d 88

任务:取出每一组的倒数三人的成绩

def top_d3(df):
    # ascending=False参数表示降序排序
    return df.sort_values(by='score', ascending=False)[-3:]
data_group.apply(top_d3)
id name part score
part
a 13 13 wZigu a 64
20 20 VjgMR a 63
7 7 CThQU a 61
b 10 10 BgoYQ b 75
9 9 YkzKn b 72
19 19 mHbyE b 69
c 26 26 mzSvn c 75
24 24 DYdgN c 63
29 29 lrsGq c 62
d 16 16 OhMaH d 75
14 14 CgNab d 69
23 23 MIcMu d 63

如上其实就是用了一个apply方法:它可以使用我们自定义的方法。

那么同样可代替的方法还有:

  1. transform:传入自定义方法(这里就不多讲了,跟apply是一样的,没意义了)

那么整个pandas的内容就到这里了,pandas非常庞大,博主也不可能说什么方法都讲,其实编程这更多的就是自己去查去学,教程能给的也就是帮忙避开一些坑,或者延伸一些东西,把知识架构拉起来,终究怎么学还是看自己啊。三篇文章的内容其实就整体已经差不多了,大家也可以自己总结一下,后面的话看情况,我可能会上传一些包含了机器学习的实战之类的。有时间了就会发的。有什么问题或者需要什么东西可以微信添加博主,如下:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_45804132/article/details/121529133