c++控制台应用每一列数据如何对齐_Python数据分析:Pandas之DataFrame

0cefc8e0663b0db916e8ed37f21d1447.png

内容目录

  • DataFrame简介
  • DataFrame创建方式
  • DataFrame索引和切片
  • DataFrame属性
  • DataFrame级联与合并
  • DataFrame基本操作
  • DataFrame分组聚合操作
  • DataFrame数据透视与交叉表

1 DataFrame简介

我们在上次课中讲到了Pandas的Series结构,还没看的点这里

ailsa:python数据分析:Pandas之Series​zhuanlan.zhihu.com
c572856bad38ed9381d740afb469b97c.png

DataFrame是一个[表格型]的数据结构,DataFrame由按一定顺序排列的多列数据组成.设计,初衷是将Series的使用场景从一维拓展到多维。其实DataFrame就是由多个Series组成的,因此可以说DataFrame是Series的容器。

DataFrame由3部分组成

行索引:index

列索引:columns

值:values

长这个样子

48e1d97d2d361543ccecfa28d3e713e8.png

是不是感觉跟Excel表格很像,跟关系型数据库表也很像,跟SPSS的表也像吧,没错,他们都是极其相似的二维表,这种形式的发明还要追溯到1978年的世界上第一款电子表格Visicalc,想要了解,可以戳这里 ailsa:1.Excel数据分析:Excel最最最基础的操作 有讲到电子表格的发展史,由此可见,二维表对于数据分析还是挺便捷的,要不然咋会有这么多分析软件都采用这种形式呢。那对于DataFrame的学习,大家可以把它想象成excel,原理都是一样的,只是一个是用鼠标点点点,一个是代码敲敲敲。

2 DataFrame创建方式

2.1 使用ndarry创建

#  DataFrame的参数组成 pd.DataFrame(data=None, index=None, columns=None, dtype=None, copy=False)
# index指定行索引,columns指定列索引,若不写,则默认从0开始,size指定行数和列数
df = pd.DataFrame(data=np.random.randint(1,10,size=(2,4)),index=["a","b"],columns=["A","B","C","D"])

a5b818f8004782e3c8ef64bf77abc435.png

2.2 使用字典创建

dic = {"name":["张三","李四","王五"],"age":[1,2,3]}
# key为列的索引,行索引则默认从0开始
pd.DataFrame(dic)

b2b15173d3443c2a29b31c8f34e50894.png

可以看出,以字典形式创建,DataFrame以字典的key作为每一列的列名,以字典的值(一个数组)作为每一列的值,DataFrame会自动加上每一行的索引

3 DataFrame的索引和切片

DataFrame也是分为显示索引和隐式索引

3.1 隐式索引的操作

df = pd.DataFrame(data=np.random.randint(1,10,size=(3,4)))

16769f1a503de86372f94319e360ffed.png
  • df[0][0] df[列][行],获取隐式索引单个元素
  • df[0:2] 对行的切片操作,获取的是0和1行,顾头不顾尾
  • df[[0,1]] 对列的操作,获取第一列和第二列,跟Series不同
  • df.iloc[0:2,0:2] iloc对于隐式索引的操作,获取前两行和前两列组成的区域,逗号前式行,逗号后是列
  • df.iloc[[0,1],[0,1]] iloc对于隐式索引的操作,获取前两行和前两列组成的区域

3.2 显式索引的操作

df1 = pd.DataFrame(data=np.random.randint(1,10,size=(3,4)),index=["a","b","c"],columns=["A","B","C","D"])

1dbb8d39bc9de55e7c83ebc44ecfc6e0.png
  • df["A"] 或 df.A 获取单列,类似于字典的操作
  • df['A']['a'] 获取单个元素,先列后行 df[列][行]
  • df["a":"b"] 获取是a到b行,包含b行
  • df[["A","B"]] 获取A列和B列
  • df.loc["a":"b","A":"B"] loc对于显式索引的操作,df[行区域,列区域]
  • df.loc[["a","b"],["A","B"]] loc对于显式索引的操作,结果同上

总结

1.DataFrame相对于Series而言,多了对于列的操作,但是是建立在Series基础之上。

2.loc是对于显式索引的相关操作(对于标签的处理),iloc是针对隐式索引的相关操作(对于整数的处理)。

3.df[0:2]切片操作是针对行而言,对于df["A"]索引操作是对于列而言;获取单个元素先列后行,df[列][行];loc和iloc操作,逗号前是行区域或行列表,逗号后是列区域或列列表。

4 DataFrame 的属性

df.values 值

df.columns 列

df.index 行

df.shape 几行几列(行,列)

df.size 大小,行数X列数

,以上面的df为事例

d9227d11351dcd98a84f683b1ac0a10e.png

5 DataFrame的级联与合并

  • 级联:pd.concat,pd.append
  • 合并:pd.merge,pd.join

5.1 级联

功能:根据指定的行或列进行值的拼接,不参与任何计算,只是把多个df变成1个

pd.concat()参数(objs, axis=0, join='outer', join_axes=None, ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, sort=None, copy=True)

  • axis=0 列方向级联拼接,axis=1行方向级联拼接,默认为0
  • join为级联方式,outer会将所有的项进行级联(忽略匹配和不匹配),取并集,而inner只会将匹配的项级联到一起,不匹配的不级联,取交集。
  • join_axes index对象列表,用于其他n-1轴的特定索引,可以指定根据哪个轴来对齐数据
  • ignore_index boolean,default False。如果为True,请不要使用并置轴上的索引值。结果轴将被标记为0,...,n-1。如果要连接其中并置轴没有有意义的索引信息的对象,这将非常有用。注意,其他轴上的索引值在连接中不受影响。
  • keys 序列,默认值无。使用传递的键作为最外层构建层次索引。如果为多索引,应该使用元组。
  • levels 序列列表,默认值无。用于构建MultiIndex的特定级别(唯一值)。否则,它们将从键推断。
  • names:list,default无。结果层次索引中的级别的名称。

示例数据

dic1 = {'A': ['A0', 'A1', 'A2', 'A3'],
       'B': ['B0', 'B1', 'B2', 'B3'],
       'C': ['C0', 'C1', 'C2', 'C3'],
       'D': ['D0', 'D1', 'D2', 'D3']}

dic2 = {'A': ['A4', 'A5', 'A6', 'A7'],
        'B': ['B4', 'B5', 'B6', 'B7'],
        'C': ['C4', 'C5', 'C6', 'C7'],
        'D': ['D4', 'D5', 'D6', 'D7']}

dic3 = {'A': ['A8', 'A9', 'A10', 'A11'],
        'B': ['B8', 'B9', 'B10', 'B11'],
        'C': ['C8', 'C9', 'C10', 'C11'],
        'D': ['D8', 'D9', 'D10', 'D11']}

df1 = pd.DataFrame(dic1,index=[0, 1, 2, 3])
df2 = pd.DataFrame(dic2, index=[4, 5, 6, 7])
df3 = pd.DataFrame(dic3, index=[8, 9, 10, 11])

pd.concat([df1,df2,df3]) # 默认是按照列方向

b3faed212eff030321e7d785ec099000.png

keys使用,作用于不同层级的名称

pd.concat([df1,df2,df3],keys=['x', 'y', 'z']) # ('x', 'y', 'z')元组也可以

79af3275c3c9dc35d2ba9c19f789794d.png

使用ignor_index

# 创建df4
dic4={'a':[1,2,3,4],'b':[5,6,7,8]}
df4 = pd.DataFrame(dic4)
df4

34edc3bc2d4712805e141f29887e94b5.png
pd.concat([df1,df4],axis=1,ignore_index=True) # 行方向进行级联

1ae3ebdb274661f4a90260c9c5aeb6a2.png

join_axes,可以指定根据哪个轴来对齐数据

#新增df5
dic5={'a':[1,2,3,4],'b':[5,6,7,8]}
df5= pd.DataFrame(dic5,index=[2,3,4,5])
df5

3ed25f6331f1057963d217ca9c34eef0.png

df1和df5行方面拼接,只有2和3是一样的

d.concat([df1,df5],axis=1,join_axes=[df1.index])

913df2909952c0350514b4fe1ed0b65c.png

效果类似于按照df1的行索引进行级联,df1的所有行会显示,而df5只能显示匹配上的

join的用法,取并集或交集

pd.concat([df1,df5],axis=1,join='outer') # 取并集,缺失值显示为NaN

efc1033b7e73bd3ef33000d722373fe7.png
pd.concat([df1,df5],axis=1,join='inner') # 取交集

e67aba624d0edddf8f037d5dfb9f49d8.png

df.append()方法,类似于添加的意思

df1.append参数:(other, ignore_index=False, verify_integrity=False, sort=None)

默认是列方向级联,跟concat的默认方式是一样的

df1.append(df2)

8e034f42d08e726c44dc4d2e75d19d5c.png

这种方式操作更简单,后面会经常使用

5.2 合并

pd.merge() 跟SQL中的连表查询很像,需要根据合并条件进行两表合并,也就是两个DataFrame需要具有相同的列,然后再进行条件连接合并,而concat单纯根据索引就能进行拼接。

参数;pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=('_x', '_y'), copy=True, indicator=False, validate=None)

  • left 和right 定义左表和右表,指定需要连接的两个DateFrame
  • how连接方式 {'left', 'right', 'outer', 'inner'}, 默认'inner'
  1. inner 内连接,只连接两个DataFrame的交集
  2. left 左连接,以左表为主,会显示左表全部内容,右表根据左表匹配,未匹配上不显示
  3. right 右连接,以右表为主
  4. outer 全外连接,会显示所有内容
  • on 如果两个Frame 指定连接条件的列名一致,可以使用这种方式
  • left_on 当两个frame列名不一致时,根据定义的左表和右表分别定义连接的字段名
  • right_on 当两个frame列名不一致时,根据定义的左表和右表分别定义连接的字段名
  • left_index 为True时,代表以索引作为连接条件
  • right_index 同上

示例

两个DataFrame列名相同且内容一致,默认自动连接

dic1 = {"name":["A","B","C","D"],"age":[20,21,22,23]}
dic2 = {"name":["A","C","D","F"],"sex":["M","F","M","M"]}
df1 = pd.DataFrame(dic1)
df2 = pd.DataFrame(dic2)
pd.merge(df1,df2) # name一列相同,自动连接
或者 pd.merge(df1,df2,on="name") 

5aa785413993613133ee37558f8f79f1.png

当连接条件列名不一致时,使用lefton 和 right_on

emp_dic = {"姓名":["张三","李四","王五"],"dep_id":[1,2,3]}
dep_dic = {"id":[1,2],"部门名称":["销售部","运营部"]}
emp = pd.DataFrame(emp_dic)
dep = pd.DataFrame(dep_dic)
pd.merge(emp,dep,left_on="dep_id",right_on="id")
SQL: select * from emp e left join dep d on e.dep_id = d.id

ab3bdf2f26b2277cd259760821e77d75.png

当连接条件为索引时,可以使用left_index 和 righti_ndex

pd.merge(emp,dep,left_on="dep_id",right_index=True) # dep_id 与dep的行索引进行匹配

5399f41c0ad655f70fbc12a3b2c4de6d.png

6 DataFrame的基本操作

6.1 缺失值处理

# 在np中
None是python自带的,其类型为object,因此,None不能参与到人任何计算中(NoneType)
np.nan(NaN) 是浮点类型(float),能参与到计算中.但计算的结果总是NaN
# 在pandas中
把None和np.nan都视作np.nan

构建示例数据

df = pd.DataFrame(np.random.randint(1,100,size=(5,4)),index=["a","b","c","d","e"],columns=["A","B","C","D"])
df1 = pd.DataFrame(data=np.random.randint(1,10,size=(3,4)),index=["a","b","c"],columns=["A","B","C","D"])
df3 = pd.concat([df1,df],axis=1) # concat级联,axis=1 行方向,后面会讲
df3

a5149bb3801db53e301a0e46f8bc9522.png

6.1.1 查看哪些行或列为存在缺失值

  • isnull() 有缺失值则返回True
  • notnull() 没有缺失值则返回True
  • isnull().any(axis=1) axis=1是代表行,0代表列,一行中只要有一个空值则返回True
  • notnull().all(axis=1) 一行中所有不为空则返回True
df3.notnull()

b8cda58d1fe541155ee33fc71acdf04e.png
df3.notnull().all(axis=1)

bd560fa04eaf9684182a2ac366914522.png

6.1.2 删除有缺失值的行或列

df.dropna() 删除有缺失值的整行或整列

f3.dropna的参数:(axis=0, how='any', thresh=None, subset=None, inplace=False)

  • axis=0 这里的0代表行,在drop操作中0代表行,1代表列,根据axis的设置决定是对行还是列
  • how='any' how是删除方式,any只要一行或一列中有一个缺失值就删除,还有一个all代表的意思是,一行或一列中所有的都为缺失值才删除,常用的是any
  • inplace=False inplace代表操作是否对原数据进行覆盖,False代表不在原数据上修改,而是复制出一份,True代表在原数据上修改。
df3.dropna()

4c11e79e39bb9398d357083e52c4bffe.png

6.1.3 填充缺失值

df.fillna() 对缺失值进行填充

df.fillna参数:(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None, **kwargs)

  • value 填充的值,也可以是字典
  • axis 1 代表行,0代表列 ,结合method使用,决定了填充是按照行还是列
  • inplace inplace代表操作是否对原数据进行覆盖,False代表不在原数据上修改,而是复制出一份,True代表在原数据上修改。
  • method 分为四种填充方式:'backfill', 'bfill', 'pad', 'ffill' 其中pad / ffill表示用前面行/列的值,填充当前行/列的空值; backfill / bfill表示用后面行/列的值,填充当前行/列的空值。

需求1:把缺失值都填充为6

df3.fillna(6)

46c2698dd622d8585a3aa50539ac2835.png

需求2:把缺失值按照列方向,填充为前面的那个值

df3.fillna(axis=0,method="ffill") # 改成pad也可以,axis确定了填充的方向,如果不写,默认是列

a1cf069608dbf91349c1136ef76458ea.png

需求3:把缺失值按照行方向,填充为后面的那个值

df3.fillna(axis=1,method="bfill")# 改成backfill也可以,axis确定了填充的方向,如果不写,

cdb70d680012e69d9d98cd217b164810.png

6.2 重复值处理

6.2.1 df.duplicated() 查看重复行

df.duplicated()的参数:(subset=None, keep='first')

  • subset 指定是哪几列重复,默认是所有的列
  • keep 有{'first', 'last', False}几种方式, 默认 'first'
  1. first 将重复项标记为“`True`”,除了第一次出现
  2. last:将重复项标记为``True`,除了最后一次出现
  3. False:将所有重复项标记为“True”

直接通过示例就能明白了

创建一个DataFrame

dic = {"A":[1,1,1,5,9],"B":[5,5,6,7,7],"C":[6,6,5,2,8]}
df = pd.DataFrame(dic)
df

2af1f7f955d0131af6ae5cb6ad0fbc41.png

需求1:把所有列重复的的行标注出来

df.duplicated() # keep默认为first,subset默认为所有的列,意思就是所有的列同时重复才显示

0848d968d50bc51c7729752c5c96845f.png

我们发现第一行和第二行所有列一样,根据keep设置的first的原则,第一次出现的不显示为True,其余的显示为True,这里的True代表重复的意思,我们只要把True的删除,就可以保留唯一值了。

需求2:把A和B两列同时重复的行显示,要求最后的那个不标注为True

df.duplicated(subset=["A","B"],keep='last')

fcd7fb07ff7bcbf283153c7f36d0b5ad.png

我们发现A和B两列同时重复的还是第一行和第二行,设置keep为last之后,第一行显示为重复行,为True,第二行显示为False。

需求3:把A和B两列重复的行全部显示为True

df.duplicated(subset=["A","B"],keep=False) 

5703c8a51a701222b679244eb31fc087.png

keep设置为False之后,所有重复的行都会显示为True

6.2.2 删除重复行,保留唯一值

对于重复行的处理,我们一般都是找出重复行,只保留一个,删除其他的,那duplicated通过keep设置来让用户自由选择是保留第一个,还是最后一个,通过显示True来实现该功能

df.drop_duplicates() 删除重复值

df.drop_duplicates参数:(subset=None, keep='first', inplace=False)

前两个就不说了,跟duplicated一样

inplace=False不在原值上删除,而是复制出一份进行操作,改成True则直接对df进行删除操作,这个也是pandas谨慎的地方,大部分操作都不是在原值上进行的,如果需要可以通过inplace进行设置

需求:删除所有列同时重复的行,默认保留第一个就行

df.drop_duplicates() # 把返回True给删除,很简便

fd4c02f640ccc5241597a2dfa94d939a.png

注意:此操作之后,原df并没有发生变化,有两种处理方式,第一种:把删除后的数据赋值给新的变量,第二种:直接修改inplace=True。

6.3 排序

  • df.sort_index() 按索引排序
  • df.sort_value() 按值排序

常用的是纵向排序,也就是默认的axis=0的相关操作

sort_index()参数(axis=0, level=None, ascending=True, inplace=False, kind='quicksort', na_position='last', sort_remaining=True, by=None)

  • axis=0 纵向排序(行索引),axis=1 横向排序(列索引)
  • ascending 排序方式,True为升序,False为降序
  • kind排序方式,默认是quicksort 快排
df=df.take(np.random.permutation(5),axis=0)
df

1c4022e426af6fa2043b25d5a6feb76b.png
df.sort_index()

f366f4e7005b1961f310e24be11f010b.png

df.sort_values()

参数:(by, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last')

  • axis=0 纵向排序(index),axis=1 横向排序(columns)
  • ascending = True 升序,False降序
  • inplace 是否在原值上直接修改,False是重新复制出一份,原frame不变
  • kind排序方式 {'quicksort', 'mergesort', 'heapsort'} 默认是quicksort 快排,mergesort归并排序,heapsort 堆排序

对某列进行排序

df.sort_values(by="C")

04c23312f0c60232829cafd30b48dbce.png
df.sort_values(by=["C","B"],axis=0,ascending=[False,True])

ec357d5013e3afc861574842dc7e07b4.png

对行进行排序

df.sort_values(by=[0,2],ascending=[False,True],axis=1)

31376630cb418db84a82363057be4b88.png

注:当存在多列或多行排序时,是有优先顺序的,根据列表中的优先顺序,在前面的优先级高,越往后优先级越低。

  • np.random.shuffle(x) 打乱原数组的顺序,shuffle直接在原数组进行修改
  • np.random.permutation(x) x可以为数组或者一个数,当为数组时,打乱原数组的顺序,不在原数组上进行,返回新的数组,不改变自身数组;当x为一个数时,则会随机排列np.arange(x)。
arr = np.array([[1,2,3],[4,3,2],[5,3,8]])
np.random.shuffle(arr) # shuffle洗牌
arr

661d09af693611af96b4cd725305e778.png
arr1 = np.array([[1,2,3],[4,3,2],[5,3,8]])
np.random.permutation(arr1) # permutation 随机排列数组
arr1

214d1ee0b724eb7c38130131e82bbbe5.png
np.random.permutation(10)

42825f2e475b39a4942b90d8bee2ae14.png
  • df.take()

df.take参数:(indices, axis=0, convert=None, is_copy=True, **kwargs)

axis=0 纵向排序,axis=1横向排序,默认为0,大部分情况下都是纵向排序

与permutation联合使用,可实现随机采样功能

示例数据

df

bcf742759c7c70f391f303329aebb813.png

对行进行随机排序,按照行索引

permutation中的x,类似于range(5),只能取到0 1 2 3 4,因此在跟take联合使用时,x的大小要跟df的行数相一致

df.take(np.random.permutation(5),axis=0)

12c5ec129a387fa1a855e472b8a01454.png
df.take(np.random.permutation(3),axis=1)

06199f181f5101ae223c328f99d92fdb.png

6.4 替换

df.replace()

df.replace参数:(to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad')

  • to_palce: 被替换的对象
  • value:替换成新的值
  • inplace: True原值上修改,False复制出一份修改
  • method {'pad', 'ffill', 'bfill', `None`}四种替换方式,默认是“pad”

单值替换

df.replace(1,10,inplace=True)

d5b6b2dc6deb94c5a1b197001aa8e020.png

多值替换

1 使用字典
dic={10:"满分",5:"中等"}
df.replace(dic) 
# 或者 使用列表
df.replace([10,5],["满分","中等"])

e1c326abf1996e613964c55d1dc22276.png

注:DataFrame中无法使用method和limit参数

6.5 映射与运算

  • map() 可以实现映射和充当运算工具,map()不是df的函数,而是Series的,因为它只针对某一列进行操作
  • apply() 只可以作为运算工具

6.5.1 map()

使用map通过字段映射,新增一列

emp_dic = {"姓名":["张三","李四","王五"],"dep_id":[1,2,3]}
emp = pd.DataFrame(emp_dic)
# 映射关系表
dic = {"张三":"Hurry","李四":"Lily","王五":"Tom"}
emp['e_name'] = emp['姓名'].map(dic)

5ddfd0074a583fa74654b3e7852cc722.png

使用map作为运算工具

df["up_num"] = df["C"].map(lambda x:x*20)

09508f8489a23040e1a07da8bcf1dcf9.png

map常跟匿名函数lambda一块使用,当然也可以使用普通函数

def complex(s):
    return s*10
df["up_num1"] = df["C"].map(complex)

8cffb454fc35b0503ecf27c10a42a178.png

注意:并不是任何形式的函数都可以作为map的参数.只有当一个函数具有一个参数且有返回值,那么该函数才可以作为map的参数

6.5.2 apply()

只能当做运算工具,当运算量很大时,建议使用apply

df['up_num2'] = df['C'].apply(lambda x:x*5)

3381ca5627ee846d97118e43b53d2b22.png

7 DataFrame的分组聚合操作

7.1 分组聚合基本操作

  1. split : 先将数据按一个属性分组 (得到 DataFrameGroupby / SeriesGroupby )
  2. apply : 对每一组数据进行操作 (取平均 取中值 取方差 或 自定义函数)
  3. combine: 将操作后的结果结合起来 (得到一个DataFrame 或 Series 或可视化图像)

使用groupby进行分组,groups查看分组情况

df.groupby参数:(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, observed=False, **kwargs)

实例数据

sale_data = pd.read_excel('./sale_data.xlsx') # 读取Excel文件

25e2b4d975672d7e4c0c4f5de2286ba5.png

需求1:计算各门店的销售数量

第一步:分组

sale_data.groupby(by="门店编码")

8955e579cbd42a76b5983807814c143e.png

这是一个DataFrameGroupby,主要的功能能是允许你在不额外写循环的情况下, 快速对每一组数据进行操作。

第二步:聚合函数

sale_data.groupby(by="门店编码").sum()

如果不指定列,则默认对所有的列都进行聚合计算

0d25285bc2cfe684850f01a1cc241122.png

题目要求对销售数量,因此修改如下:

sale_data.groupby(by="门店编码")["销售数量"]

71eb18e10c14148c38b2a65a9f24f58e.png

这是一个SeriesGroupBy对象,在不用循环的情况实现聚合计算

sale_data.groupby(by="门店编码")["销售数量"].sum()

ed7e927a9bc866491608051a268d8a4b.png

得到每个门店的销售数量总和是一个Series,聚合函数,还可以使用

std(标准差)、median(中位数)、min(最大值)、max(最小值)、mean(均值)

查看分组情况

sale_data.groupby(by="门店编码").groups

9c8650b0150fea7147d65886d180794b.png

需求2:计算每个产品的均价,并新增一列到sale_data?

mean_price = sale_data.groupby(by="产品编码")["单价"].mean()
mean_dic = mean_price.to_dict() # to_dict转换成字典形式
mean_dic

389514146ad21bc72af3e570e6b5656a.png
sale_data["mean_price"] = sale_data["产品编码"].map(mean_dic)

795b9cd123efd54aa69181d5b1b7617c.png

7.2 分组聚合高级操作

使用groupby分组后,也可以使用transform和apply提供自定义函数实现更多的运算

sale_data.groupby(by="门店编码")["销售数量"].sum()

等价于 sale_data.groupby(by="门店编码")["销售数量"].apply(sum),然后对sum函数进行定义,这里的一些常用聚合函数,是pandas给定义好的,我们根据实际需要可以进行自定义

模拟mean函数实现对于不同产品的平均价格计算

# 定义求平均函数
def my_mean(s): # 使用apply传入的是分组后的,因此是一个Series
    sum_num = 0
    n=0
    for i in s:
        sum_num+=i
        n+=1
    return sum_num/n
# 实现分组聚合计算
sale_data.groupby(by="产品编码")["单价"].apply(my_mean)

5d199b92c5426adca7965e02f224de36.png
# 使用transform返回的是原始数据每一行的值,对原数据结构并没有进行任何修改
sale_data.groupby(by="产品编码")["单价"].transform(my_mean)

896200172be29836588bb542db21abdb.png

7.3 agg聚合操作

全称:aggregate

sale_data.agg({"销售数量":["sum","mean"],"单价":["sum","mean"]}) # aggregate

1af6e1b7c1d68ac69f7571453484db49.png

8 DataFrame数据透视表与交叉表

8.1 DataFrame数据透视

这个数据透视表跟Excel中的数据透视功能是一样的,也是分组计算的一种方式,只能这种方式比groupby更加方便快捷,可操作性强,灵活好用。

df.pivot_table() 数据透视

参数:(values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All')

  • values: 对哪些列进行聚合计算,可以指定一列或多列
  • index:根据哪一列进行行方向分组,也就是分组条件,这个是必须要有的,类似groupby中by,或者是Excel数透中的行标签
  • columns: 根据哪一列进行列方向进行分组,类似于Excel数据透视的列标签
  • aggfunc:聚合计算方式,也就是对应的聚合函数操作

示例还是上面的销售数据

需求1: 计算每个门店的总销售数量

sale_data.pivot_table(index="门店编码",values="销售数量",aggfunc="sum")

d0663346c224b2e0e53b3c5811303418.png

需求2:计算每个门店的每个产品的销售数量

sale_data.pivot_table(index="门店编码",columns="产品编码",values="销售数量",aggfunc="sum")

42ceabd46801b5c1633c71701650ffb1.png

需求3: 计算2016年每月的每家门店的销售数量和平均单价

sale_data.pivot_table(index=["月份","门店编码"],values=["销售数量","单价"],aggfunc=["sum","mean"])

46ed067cbea4d4626225856114398280.png

8.2 DataFrame交叉表

pd.crosstab() 主要用于分类数据计数,类似于列联表

参数;(index, columns, values=None, rownames=None, colnames=None, aggfunc=None, margins=False, margins_name='All', dropna=True, normalize=False)

  • index 交叉表的行标签
  • columns 交叉表的列标签
pd.crosstab(sale_data["门店编码"],sale_data["产品编码"])

总结:

1 groupby对原DataFrame进行分组操作,返回DataFrameGroupby或SeriesGroupBy对象,在此基础上可直接进行采用已定义好的聚合函数进行计算。

2 使用apply和transform可以实现对于聚合操作的自定义,根据自己独有的规则设计函数,采用apply对已分组后的数据进行计算,返回的是分组后的计算结果。

3 apply和transform最大的不同在于,apply返回的分组后的列+分组后的计算结果,他已经改变了原始表的结构,而transfrom返回的是原始分组的列,以及对应的每一行的结果,保留了原始表的所有的。类似于SQL中的聚合函数和开窗函数的区别。

4 map是Series的方法,传入的是每个值,而apply既可以用于Series也可以用于DataFrame,并且用于DataFrame时传入的是一个Series,而用于Series时传入的是个值,transform用法与apply一致,只是返回的结果保持跟源数据结构一致。

5 aggregate用法比groupby更加简便。

pandas是python数据分析三剑客中非常重要 一员,所以写的内容比较细,比较多,希望能够对大家有所帮助。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值