一、向量化函数
向量化函数是指将输入参数为向量的函数,通过对向量进行操作,得到输出为向量的函数。在数学和计算机科学领域中,向量化函数通常用于加速计算和提高代码的可读性。
1.向量化函数展示
import pandas as pd
import numpy as np
df=pd.DataFrame({'a':[10,20,30],'b':[20,30,40]})
df
def avg_1(x,y):
return (x+y)/2
avg_1(df['a'],df.b)
def avg_2(x,y):
#如果x列传入20,就返回空
if x==20: #此处报错,x是向量,20是标量,他们无法做判断
return np.NaN
return (x+y)/2
avg_2(df['a'],df.b)
此处报错原因其实就是向量和标量之间无法比较,需要通过以下向量化函数解决该问题,
方法一:np.vectorize(要被向量化的函数)
# 6. 使用 np.vectorize 将函数向量化.
# 写法1: 通过 np.vectorize(要被向量化的函数名) 方式实现.
avg_2_mod_vec = np.vectorize(avg_2_mod)
avg_2_mod_vec(df['a'], df['b'])
方法二:装饰器方式,即在那个有问题的函数的上一行@np.vectorize即可
#方法二: 通过装饰器方式实现,再要被向量化函数的上加上@np.vectorize
@np.vectorize
def avg_3(x,y):
#如果x列传入20,就返回空
if x==20: #此处报错,x是向量,20是标量,他们无法做判断
return np.NaN
return (x+y)/2
avg_3(df['a'],df.b)
2.lambda表达式
当函数比较简单的时候, 就没有必要创建一个def 一个函数, 可以使用lambda表达式创建匿名函数,格式: lambda 形参列表 :函数体
# 基于上面已经创建好的df对象继续操作
# 原始方法:
def my_fun(x):
return x+1
df.apply(my_fun)
# lambda表达式:
df.apply(lambda x : x+1) # 效果同上
df.apply(lambda x : x**2)
# 统计每列非空值数量
# x表示1个Series对象
df.apply(lambda x :x.isnull().count())
# df对象的函数
df.isnull().count()
二、数据分组
python中的分组groupby()类似于SQL中的group by 分组字段,按照不同取值进行分组。
一、分组+聚合
1.首先导入gapminder数据
import pandas as pd
import numpy as np
df=pd.read_csv('./gapminder.tsv',sep='\t')
df
简单看下数据
2.需求:统计不同年份平均年龄
df.groupby('year').lifeExp.mean()
3.需求:统计不同大洲平均年龄
# 这里给大家提供多种写法
# 1.标准写法中括号
df.groupby('continent')['lifeExp'].mean()
# 2.df.列名
df.groupby('continent').lifeExp.mean()
# 2.结合agg()或aggregate()函数实现,完全一样
df.groupby('continent').lifeExp.agg('mean')#这个mean时numpy里的,需要加''包裹
df.groupby('continent').lifeExp.aggregate('mean')
# 3.上述格式变形写法,{要操作的列1:聚合函数1,.....}
df.groupby('continent').agg({'lifeExp':'mean'})
# 4.直接传入numpy包下的函数
df.groupby('continent').lifeExp.agg(np.mean)
df.groupby('continent').agg({'lifeExp':np.mean})
也可以通过自定义函数的方式,但不推荐在这里使用,这个需求用一句简单的代码就可以搞定喽
# 5.传入自定义函数,计算平均值
def my_mean(col):
return col.mean()
df.groupby('continent').lifeExp.agg(my_mean)
df.groupby('continent').agg({'lifeExp':my_mean})
但是下面这个需求,可以用用它
4.计算全球平均寿命的平均值和分组之后平均值的差值
# 根据年份分组计算每年平均寿命,用每年平均寿命-平均寿命列的平均值
def my_mean_diff(col,global_value):
"""
:param col: 某年所有的平均寿命值
:param global_value: 全球平均寿命
:return:
"""
return my_mean(col)-global_value
# df.lifeExp.mean()
# df.groupby('year').lifeExp.mean()
df.groupby('year').lifeExp.agg(my_mean_diff,global_value=df.lifeExp.mean())
二、分组+转换
这里需要用到transform()函数,需要把DataFrame中的值传递给一个函数, 而后由该函数"转换"数据,它与不同聚合不同的是,不会减少数据量。
来个小案例,用transform填充缺失值
import pandas as pd
import numpy as np
tips=pd.read_csv('dataset04/tips.csv')
tips
# 随机抽10条数据,random_state表示随机种子,每次抽到的结果都是一样的
tips10=tips.sample(10,random_state=6)
tips10
#np.random.permutation(字段)根据传入的内容进行随机打乱顺序
tips10.loc[np.random.permutation(tips10.index)[:4],'total_bill']=np.NaN
tips10
# 查看缺失值
tips10.groupby('sex').count()
# 自定义函数用每组平均值填充每组缺失值
def my_fill_na(col):
return col.fillna(col.mean())
tips10.groupby('sex').total_bill.transform(my_fill_na)
三、分组+过滤
还是基于tips数据,调用filter 方法,传入一个返回布尔值的函数,返回False的数据会被过滤掉
# 需求: 根据就餐人数进行分组, 过滤掉条目数少于30条的组
# 1. 使用小费数据
tips = pd.read_csv('data/tips.csv')
# 2. 查看用餐人数
tips['size'].value_counts()
# 3. 人数为1、5和6人的数据比较少,考虑将这部分数据过滤掉
tips_filtered = tips.groupby('size').filter(lambda x: x['size'].count() > 30)
# 4. 查看结果
tips_filtered['size'].value_counts()
# 5. 合并版写法
tips.groupby('size').filter(lambda x: x['size'].count() > 30)['size'].value_counts()
三、透视表
1.不利用透视表解决需求,使用会员信息查询数据集举例
# 导入数据
import pandas as pd
custom_info=pd.read_excel('dataset04/会员信息查询.xlsx')
custom_info
from datetime import datetime
# 1.原数据中没有年月字段,要将日期列转为年月字段加入到df对象中
# custom_info[]=custom_info['注册时间'].apply(lambda x:x.strftime('%Y-%m'))
custom_info.loc[:,'注册年月']=custom_info['注册时间'].apply(lambda x:x.strftime('%Y-%m'))
custom_info
# 2.计算每月的会员月增量
custom_info[['会员卡号','会员等级','会员来源','注册年月']]
month_count=custom_info.groupby('注册年月')[['会员卡号']].count()
month_count.columns=['月增量']
month_count
2.利用透视表解决需求
首先了解以下透视表pivot_table,它有四个重要参数:
(1)values: 要做聚合操作的列名
(2)index: 行索引, 传入原始数据的列名, 这一列中每个取值会作为透视表结果的1个行索引.
(3)columns: 列索引, 传入原始数据的列名, 这一列中每个取值会作为透视表结果的1列.
(4) aggfunc: 聚合函数
# 增量会员等级分布
member_rating=custom_info.pivot_table(index='注册年月',columns='会员等级',values='会员卡号',aggfunc='count')
member_rating=member_rating[1:]