3.Pandas数据处理

3.1 Apply自定义函数

3.1.1 apply介绍

pandas 的 apply() 函数可以作用于 Series 或者整个 DataFrame,功能也是自动遍历整个 Series 或者 DataFrame, 对每一个元素运行指定的函数。

  • Pandas提供了很多数据处理的API,但当提供的API不能满足需求的时候,需要自己编写数据处理函数, 这个时候可以使用apply函数
  • apply函数可以接收一个自定义函数, 可以将DataFrame的行/列数据传递给自定义函数处理
  • apply函数类似于编写一个for循环, 遍历行、列的每一个元素, 但比使用for循环效率高很多

3.1.2 Series的apply自定义函数【重点】

  • Series的apply自定义函数接收的参数x是一个数值
def my_exp(x,e):
    return x+e
# series.apply(自定义函数名, args=(参数1, 参数2, ...)) 
# args参数必须接收一个元祖;没有参数就不用写args=
df['列名'].apply(my_exp, args=(3,))
复制代码

3.1.3 DataFrame的apply自定义函数【重点】

使用方法和Series的apply自定义函数的用法一致,比如对自定义函数传入多个参数的用法都是一样的

  • 默认按列遍历执行

    • df的apply自定义函数接收的参数x默认是一列数据
def my_exp2(x):
    return x+2
df.apply(my_exp2)

复制代码
  • 按行遍历执行

    • 参数axis=1使x的值是一行数据
def my_exp2(x):
    return x+2
df.apply(my_exp2, axis=1)
复制代码
  • 按df中的每一个值遍历执行
def my_exp2(x):
    return x+2
df.applymap(my_exp2)
复制代码

3.1.4 函数向量化【知道】

  • np.vectorize()
def foo(x, y):
    if x != 0: # x,y都是series对象,不能和数字类型做比较判断
        return x + y
# foo(df['列名1'], df['列名2']) # 报错!

import numpy as np
bar = np.vectorize(foo)
bar(df['列名1'], df['列名2'])
复制代码
  • 对自定义函数使用装饰器
import numpy as np
@np.vectorize
def foo(x, y):
    if x != 0: # x,y都是series对象,不能和数字类型做比较判断
        return x + y
foo(df['列名1'], df['列名2'])
复制代码

3.1.5 lambda匿名函数【重点】

  • 概念

    • 不用写函数名字的函数表达式,可以作为参数直接使用
  • 作用

    • 让代码更加精简
    • 提高代码可读性
    • 不需要考虑函数命名的问题
  • 用法

# 关键字lambda表示匿名函数,冒号前是参数,可以有多个,用逗号隔开,冒号右边的返回值
df.apply(lambda x: x+1)
复制代码

3.2 数据分组

3.2.1 agg和aggregate聚合【重点】

  • 分组后单列使用多个聚合函数

    • 同时使用多个内置聚合函数或者numpy聚合函数,全部放入一个Python列表中, 然后把整个列表传入agg或aggregate中;返回以分组列作为索引,每一个聚合计算结果作为列的全新df
df.groupby('列名1').列名2.agg(['max', 'min']) 
# max, min 为pandas内置的聚合函数名
# 也可以传入numpy的聚合函数,np.mean,np.max
df.groupby('列名1').列名2.agg(['max',np.mean]) 
复制代码
  • 分组后对多列分别使用聚合函数

    • agg函数中可以传入字典,字典的key是df的列名,与key对应的value是pandas内置的聚合计算函数、其名称的字符串;;返回以分组列作为索引,每一个聚合计算结果作为列的全新df
df.groupby('列名1').agg({
    '列名2':'mean', 
    '列名3':'sum', 
    '列名4':np.max
})
复制代码
  • 分组后使用自定义聚合函数
def my_mean(values, args1, args2):
    '''自定义的计算平均值函数
    values是固定参数,为传入的series对象
    '''
    args1+args2
    n = len(values) # 获取数据条目数
    sum = 0
    for value in values:
        sum += value
    return(sum/n)
  
# 调用自定义函数
df.groupby('列名1')['列名2'].agg(my_mean, args1=xxx, args2=xxx)
复制代码

.2.2 transform转换【重点】

transform 转换,需要把DataFrame中的值传递给一个函数, 而后由该函数”转换”数据。

aggregate(聚合) 返回单个聚合值,分组列有多少组就返回多少条数据,但transform 不会减少数据量

  • 分组后使用内置函数

    • 根据列名1分组后,对列名2的值做聚合计算,返回series对象
df.groupby('列名1')['列名2'].transform('sum')
# sum是pandas内置聚合函数的函数名,求和
复制代码
  • 分组后使用自定义函数
# 自定义一个计算函数
def foo(x, y):
    return x + y
df.groupby('列名1')['列名2'].transform(foo, y=3)
复制代码

3.2.3 filter过滤【重点】

  • groupby方法后接filter方法,filter传入一个返回布尔值的匿名函数,该函数的入参就是groupby分组之后的每一组数据,返回False的数据会被过滤掉;最终返回新的df数据
df.groupby('列名').filter(匿名函数)
复制代码

3.2.4 DataFrameGroupBy对象【了解】

  • 查看groupby分组后每一个分组对象中数据所在的行
df.groupby('列名').groups

# 返回字典 {'Female': [198, 124, 101], 'Male': [24, 6, 153, 211, 176, 192, 9]}
# 那么df分组列中一定只有Female和Male两种数据
# 字典中的key是原df中分组列的类别值;value是一个python列表,里面的数字是是原始数据df的行索引值
复制代码
  • 根据分组列的列值获取分组对象并返回df
df.groupby('列名').get_group('分组列中的某个类别值')
复制代码
  • 分组对象只能遍历不能用下标获取具体的分组
for group in df.groupby('列名'):
    print(group)

### 以下代码是错误的!!!
df.groupby('列名')[0] 
复制代码

3.3 数据透视表

3.3.1 概念

数据透视表就是基于原数据表、按照一定规则呈现汇总数据;和excel的透视表在数据呈现上功能相同

3.3.2 pivot_table()用法【重点】

pd.pivot_table(
  	data, # 要透视操作的df
    index='列名1', # 分组的列名作为行索引
    columns='列名2', # 分组的列名作为列索引
    values='列名3',  # 要聚合的列
    aggfunc='内置聚合函数名', # 聚合函数 
    margins=True # 默认是False, 如果为True,就在最后一行和最后一列,按行按列分别执行aggfunc参数规定的聚合函数
)
复制代码
  • 使用说明:以列名1作为索引,根据列名2进行分组,对列名3使用pandas内置的聚合函数进行计算,返回新的df对象

  • 参数说明:

    • index:返回df的行索引,并依据其做分组;传入原始数据的列名
    • columns:返回df的列索引;传入原始数据的列名,根据该列做分组
    • values: 要做聚合操作的原始数据的列名
    • aggfunc:内置聚合函数名字符串

3.4 datetime数据类型【知道】

3.4.1 pandas中的数据转换成datetime

  • pd.to_datetime()
df['列名'] = pd.to_datetime(df['列名'])
复制代码
  • 加载数据时通过时parse_dates=[列下标/列名]
pd.read_csv('path', parse_dates=[列下标/'列名']) 
复制代码

3.4.2 提取日期中的各个部分

  • 时间戳类型对象提取日期中的各个部分
d = pd.to_datetime('2020-06-20') 
# d ==> Timestamp('2020-06-20 00:00:00')
d.year
d.month
d.day
d.hour
d.minute
d.second
d.quarter # 季度
d.weekday() # 星期几 0是星期一 1是星期二 6是星期日
复制代码
  • df列中的时间日期对象提取日期中的各个部分
df['Date'].dt.year
df['Date'].dt.month
df['Date'].dt.day
df['Date'].dt.hour
df['Date'].dt.minute
df['Date'].dt.second
df['Date'].dt.quarter # 季度
复制代码

3.4.3 日期运算和Timedelta类型

  • 直接调用聚合函数
df['Date'].min() 
复制代码
  • 直接进行时间差运算
df['Date'] - df['Date'].min()
# 结果是timedelta类型
复制代码

3.4.4 日期时间类型索引

时间序列数据,连续的按照一定时间距离或时间点记录的数据

  • 将datetime时间类型的列设为df的索引就变为DatetimeIndex类型此时可以分别按年月日取出数据
# 设定时间类型列为索引列
df.index = df['Date'] 
# 此时索引列值的样子是 2015-08-19
df['2016'] # 按年取子集df
df['2016-06'] # 按年月取子集df:所有符合条件的完整行数据
####注意!!!以上是日期时间类型行索引为连续的日期获取数据操作####

#当日期时间类型行索引不是连续的时候通过以下方法获取数据,df.loc[]
df.loc['2016']
df.loc['2016-06']
复制代码
  • 将timedelta时间差类型的列设为df的索引就变为TimedeltaIndex类型此时可以按范围取出数据
# 设定timedelta时间差类型为索引列
df.index = df['Date'] - df['Date'].min()
# 此时索引列值的样子是
#0 days
#1 days
#2 days
#...
# 此时可以用范围取子集df:所有符合条件的完整行数据
tesla['0 days':'4 days']
复制代码

3.4.5 pd.date_range()

  • 生成连续的DatetimeIndex类型数据
pd.date_range(start='2014-12-31', end='2015-01-05', freq='D')
# 参数freq='D'表示连续的日期
# 参数freq='B'表示只返回工作日

#### 返回如下 ####
###########################################
DatetimeIndex(
    [
        '2014-12-31', 
        '2015-01-01', 
        '2015-01-02', 
        '2015-01-03',
        '2015-01-04', 
        '2015-01-05'
    ],
    dtype='datetime64[ns]', 
    freq='D' # freq参数详见最后 时间周期参数
)
###########################################
复制代码

3.4.6 df.reindex()

  • 用连续的DatetimeIndex类型数据重建不连续的DatetimeIndex索引
df.index = df['Date']
date_range = pd.date_range(start='2014-12-31', end='2015-01-05', freq='D')
df = df.reindex(date_range)
复制代码

3.4.7 df.between_time()

  • 对DatetimeIndex作为索引的df可以按起止时间查询完整数据行
# between_time函数,include_end=False表示不包含结束时间,默认为True,同样也有include_start参数
df.between_time('4:00', '5:00', include_end=False)
复制代码

3.4.8 df.at_time()

  • 对DatetimeIndex作为索引的df可以按时间点采样返回完整数据行
df.at_time('5:47')
复制代码

3.4.9 df.set_index()

  • 将某列设置为df的行索引
df = df.set_index('列名')
# df.reset_index() 重置索引
复制代码

3.4.10 df.sort_index()

  • 对行索引进行排序操作
df = df.sort_index()
# 默认升序,ascending=False降序
复制代码

3.4.11 df.resample()

  • 按时间序列分组统计
df.resample('W').size() # 按每周统计数据的总数
df.resample('Q')['列名1', '列名2'].sum() # 按每季度对指定列进行聚合统计
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享