数据分析从0到1----Pandas篇(五)

本文涉及的产品
公网NAT网关,每月750个小时 15CU
简介: 数据分析从0到1----Pandas篇

缺失值

缺失值类型

在pandas中,缺失数据显示为NaN。缺失值有3种表示方法,np.nan , None , pd.NA

1、np.nan

缺失值有个特点,它不等于任何值,连自己都不相等。如果用nan和任何其它值比较都会返回nan

print(np.nan == np.nan)
print(type(np.nan))
print(pd.Series([1,2,3]).dtype) # 数据中全为int 那么就是int类型
print(pd.Series([1,np.nan,3]).dtype) # 数据中有一个nan,那么类型变为float

初学者做数据处理遇见object类型会发懵,不知道这是个啥,明明是字符型,导入后就变了,其实是因为缺失值导致的。

除此之外,还要介绍一种针对时间序列的缺失值,它是单独存在的,用NaT表示,是pandas的内置类型,可以视为时间序列版的np.nan,也是与自己不相等

t = pd.Series([pd.Timestamp('20220101')]*3)
print(t)
t[2]=np.nan
print(t)

2、None

还有一种就是None,它要比nan好那么一点,因为它至少自己与自己相等

print(None == None)
print(pd.Series([1,None]))

3、NA标量

pandas1.0以后的版本中引入了一个专门表示缺失值的标量pd.NA,它代表空整数、空布尔值、空字符

对于不同数据类型采取不同的缺失值表示会很乱。pd.NA就是为了统一而存在的。pd.NA的目标是提供一个缺失值指示器,可以在各种数据类型中一致使用(而不是np.nan、None或者NaT分情况使用)。

s = pd.Series([1,2],dtype='Int64')
print(s)
s[1]=pd.NA
print(s)

### pd.NA的一些常用算术运算和比较运算的示例:
# 加法
print('pd.NA+1:\t',pd.NA+1)
# 乘法
print('a*pd.NA:\t','a'*pd.NA)
# 以下两种其中结果为1
print('pd.NA ** 0 :\t',pd.NA**0)
print('1 ** pd.NA:\t',1**pd.NA)
### 比较运算
print('pd.NA == pd.NA:\t',pd.NA==pd.NA)
print('pd.NA < 2.5:\t',pd.NA < 2.5)
print('np.add(pd.NA,1):\t',np.add(pd.NA,1))

缺失值处理

上面讲解完了缺失值的类型,现在讲解一下如何处理缺失值

对于缺失值一般有2种处理方式,要么删除,要么填充(用某个值代替缺失值)。缺失值一般分2种,

  • 一种是某一列的数据缺失。
  • 另一种是整行数据都缺失,即一个空行

首先先来获取缺失值

df = pd.read_excel('16-data/data_test.xlsx')
print(df)
print('---------------------')
print(df.info()) # 查看缺失值的情况
print(df.isnull()) # 缺失值的判断

之后就是对这些缺失值要进行那些处理了,可以进行删除,也可以进行填充

删除缺失值

df. dropna(axis=0, how='any', thresh=None,subset=None,inplace=False)

  • axis:{0或’index’,1或columns"}默认为0确定是否删除了包含缺少值的行或列
    0或“索引”:删除包含缺少值的行。
    1或“列”:删除包含缺少值的列。
  • how:{any’,'all},默认为’any’确定是否从DataFrame中删除行或列,至少一个NA或所有NA.
    “any”:如果存在任何NA值,请删除该行或列。
    “all”:如果所有值都是NA,则删除该行或列。
  • thresh: int需要至少非NA值数据个数。
  • subset:定义在哪些列中查找缺少的值
  • inplace:是否更改源数据
df = pd.DataFrame({'name':['张','三','李','四'],
                  'toy':[np.nan,'dog','cat','mouse'],
                  'born':[pd.NaT,pd.Timestamp('1940-04-25'),pd.NaT,pd.Timestamp('2022-01-02')]})
print(df)
# 删除至少缺少一个元素的行
print(df.dropna())
# 删除至少缺少一个元素的列
print(df.dropna(axis='columns'))
# 删除缺少所有元素的行
print(df.dropna(how='all'))
# 仅保留至少有2个非NA值的行
print(df.dropna(thresh=2))
# 定义在那些列中查找缺少的值
print(df.dropna(subset=['toy']))
# 在同一个变量中保留操作数据
print(df.dropna(inplace=True))
print(df)

如果有缺失值,还可以进行缺失值补充操作

用平均值填充,

用众数填充(大多数时候用这个),众数是指一组数据中出现次数最多的那个数据,一组数据可以有多个众数,也可以没有众数

向前填充(用缺失值的上一行对应字段的值填充,比如D3单元格缺失,那么就用D2单元格的值填充)、

向后填充(与向前填充对应)等方式。

df.fillna(value=None,method=None,axis=None,inplace=False,limit=None,downcast=None)

  • value:用于填充的值(例如0),或者是一个dict/Series/DataFrame值,指定每个索引(对于一个系列)或列(对于一个数据帧)使用哪个值。不在dictSeries/DataFrame中的值将不会被填充。此值不能是列表。
  • method :ffiIl->将上一个有效观察值向前传播 bfill–>将下一个有效观察值向后传播
  • axis :用于填充缺失值的轴。
  • inplace :是否操作源数据
df = pd. DataFrame([
                    [np.nan,2,np.nan,0],
                    [3,4,np.nan,1],
                    [np.nan,np.nan,np.nan,np.nan],
                    [np.nan,3,np.nan,4]
                    ],
                    columns=['A','B','C','D']
                )
print(df)
#将所有NaN元素替换为0
print(df.fillna(0))
# 我们还可以向前或者向后传播非空值
print(df.fillna(method='ffill'))
print(df.fillna(method='bfill'))
# 将列'A','B','C','D'中的所有NaN元素分别替换为0,1,2,3
values = {'A':0,'B':1,'C':2,'D':3}
df.fillna(value=values)
# 只替换第一个NaN元素
df.fillna(0,limit=1)
# 当使用数据填充时,替换会沿着相同的列名和索引进行
df2 = pd.DataFrame(np.random.rand(4,4),columns=['A','B','C','E'])
print(df2)
print('--------------')
print(df)
df.fillna(value=df2)

分组操作

在数据分析中,经常会遇到这样的情况:

根据某一列(或多列)标签把数据划分为不同的组别,然后再对其进行数据分析。

比如,某网站对注册用户的性别或者年龄等进行分组,从而研究出网站用户的画像(特点)。在 Pandas中,要完成数据的分组操作,需要使用groupby()函数,它和 SQL的GROUP BY操作非常相似。

在划分出来的组(group)上应用一些统计函数,从而达到数据分析的目的,比如对分组数据进行聚合、转换,或者过滤。这个过程主要包含以下三步:

  • 拆分(Spliting):表示对数据进行分组;
  • 应用(Applying):对分组数据应用聚合函数,进行相应计算;
  • 合并(Combining):最后汇总计算结果。

在pandas中,实现分组操作的代码很简单,仅需一行代码,在这里,将上面的数据集按照name字段进行划分:

list1 = ['A','B','C']
[list1[x] for x in np.random.randint(0,len(list1),10)]
data = pd.DataFrame({
    'name':[list1[x] for x in np.random.randint(0,len(list1),10)],
    'age':np.random.randint(5,50,10),
    'money':np.random.randint(15,50,10)
})
print(data)
print('---------')
group = data.groupby('name')
print(group)

上述代码会返回一个DataFrameGroupBy对象

那这个生成的DataFrameGroupBy是啥呢?

对data进行了groupby后发生了什么?

python所返回的结果是其内存地址,并不利于直观地理解,为了看看group内部究竟是什么,这里把group转换成list的形式来看一看:

print(list(group))
group.groups

转换成列表的形式后,可以看到,列表由三个元组组成,每个元组中,

第一个元素是组别(这里是按照name进行分组,所以最后分为了A,B,C),

第二个元素的是对应组别下的DataFrame,整个过程可以图解如下:

聚合操作

聚合(Aggregation)操作是groupby后非常常见的操作,会写SQL的朋友对此应该是非常熟悉了。聚合操作可以用来求和、均值、最大值、最小值等

例如

min----求最小

max----求最大

count----计数

mean----求平均

median----求中位数

std----求标准差

var----求方差

print(data.groupby('name').agg('mean')) # 显示声明聚合调用mean方法
print(data.groupby('name').mean()) # 直接调用聚合的mean方法

如果想对针对不同的列求不同的值,比如要计算不同公司员工的平均年龄以及薪水的中位数,可以利用字典进行聚合操作的指定:

data.groupby('name').agg({'age':'max','money':'min'})

转换

transform转换值

transform是一种什么数据操作?

和agg有什么区别呢?

为了更好地理解transform和agg的不同,下面从实际的应用场景出发进行对比。在上面的agg中,我们学会了如何求不同name员工的平均money和age,

如果现在需要在原数据集中新增一列avg_money,代表员工所在的公司的平均薪水(相同公司的员工具有一样的平均薪水),该怎么实现呢?

如果按照正常的步骤来计算,需要先求得不同公司的平均薪水,然后按照员工和公司的对应关系填充到对应的位置,不用transform的话

print(data.groupby('name').mean()['money'])
avg_money_dict = data.groupby('name')['money'].mean().to_dict()
print(avg_money_dict)
avg_money = data[['name','money']].groupby('name')['money'].mean().to_dict()
print(avg_money)
# map()函数可以用于Series对象或DataFrame对象的一列
# 接收函数或字典对象作为参数,返回结果函数或字典映射处理后的值
data['avg_money']=data['name'].map(avg_money)
print(data)
print('---------------------------')
# 如果使用transform的话,只需要一行代码
data['avg_money']=data.groupby('name')['money'].transform('mean')
print(data)

还是以图解的方式来看看进行groupby后transform的实现过程(为了更直观展示,

图中加入了name列,实际按照上面的代码只有money列):

图中的大方框是transform和agg所不一样的地方,对agg而言,会计算得到A,B,C公司对应的均值并直接返回,但对transform而言,则会对每一条数据求得相应的结果,同一组内的样本会有相同的值,组内求完均值后会按照原索引的顺序返回结果,如果有不理解的可以拿这张图和agg那张对比一下。

Apply

它相比agg和transform而言更加灵活,能够传入任意自定义的函数,实现复杂的数据操作对于groupby后的apply,以分组后的子DataFrame作为参数传入指定函数的,基本操作单位是DataFrame

假设我现在需要获取各个公司年龄最大的员工的数据,该怎么实现呢?可以用以下代码实现:

def get_oldest_staff(x):
    # 输入的数据按照age字段进行排序
    df = x.sort_values(by='age',ascending=True)
    # 返回最后一条数据
    return df.iloc[-1]
oldest_staff = data.groupby('name',as_index=False).apply(get_oldest_staff)
print(oldest_staff)

虽然说apply拥有更大的灵活性,但apply的运行效率会比agg和transform更慢。所以,groupby之后能用agg和transform解决的问题还是优先使用这两个方法,实在解决不了了才考虑使用apply进行操作

合并

为了方便维护,一般公司的数据在数据库内都是分表存储的,比如用一个表存储所有用户的基本信息,一个表存储用户的消费情况。所以,在日常的数据处理中,经常需要将两张表拼接起来使用,这样的操作对应到SQL中是join,在Pandas中则是用merge来实现。这就讲一下merge的主要原理。

上面的引入部分说到merge是用来拼接两张表的,那么拼接时自然就需要将用户信息一 一对应地进行拼接,所以进行拼接的两张表需要有一个共同的识别用户的键(key)。总结来说,整个merge的过程就是将信息一 一对应匹配的过程,下面介绍merge的四种类型,分别为inner,left , right和outer 。

pd.merge(left,right,how: str = 'inner',on=None,left_on=None,right_on=None,left_index: bool =False,right_index: bool = False,sort: bool =False,suffixes=('_x', 'Y'),copy: bool = True,

indicator: bool = False,validate=None,)

先来看一下数据对应的情况,分为一一对应和一对多两种情况

# 一条数据对应一条数据
df1 = pd.DataFrame({
    'userid':['a','b','c','d'],
    'age':[12,13,14,15]
})
df2 = pd.DataFrame({
    'userid':['a','c'],
    'money':[123,543]
})
print(pd.merge(df1,df2,on='userid')) # 第一种合并方法
print('------------------------')
print(df1.merge(df2,on='userid')) # 第二种方法合并

# 一条数据对应多条数据
df1 = pd.DataFrame({
    'userid':['a','b','c','d'],
    'age':[12,13,14,15]
})
df2 = pd.DataFrame({
    'userid':['a','c','a','b'],
    'money':[123,543,546,123]
})
print(df1.merge(df2,on='userid'))
print('------------')
print(pd.merge(df1,df2,on='userid'))

'left和’right的merge方式其实是类似的,分别被称为左连接和右连接。这两种方法是可以互相转换的,所以在这里放在一起介绍。

‘left’

merge时,以左边表格的键为基准进行配对,如果左边表格中的键在右边不存在,则用缺失值NaN填充。

‘right’

merge时,以右边表格的键为基准进行配对,如果右边表格中的键在左边不存在,则用缺失值NaN填充。

简而言之也就是:左连接,则左表的所有数据都必须显示,右表只是填充对应的数据而已,

右连接则与左连接相反.

什么意思呢?用一个例子来具体解释一下,这是演示的数据

# 左连接
df1 = pd.DataFrame({
    'userid':['a','b','c','d'],
    'age':[12,13,14,15]
})
df2 = pd.DataFrame({
    'userid':['a','c','e'],
    'money':[123,543,546]
})
print(df1.merge(df2,on='userid',how='left'))
print('------------')
print(pd.merge(df1,df2,on='userid',how='left')) # 左连接

# 右连接
df1 = pd.DataFrame({
    'userid':['a','b','c','d'],
    'age':[12,13,14,15]
})
df2 = pd.DataFrame({
    'userid':['a','c','e'],
    'money':[123,543,546]
})
print(df1.merge(df2,on='userid',how='right'))
print('------------')
print(pd.merge(df1,df2,on='userid',how='right')) # 右连接

与此同时还有一个outer外连接,他将展示量表所有的信息,没有对应的则为NaN

# 外连接
df1 = pd.DataFrame({
    'userid':['a','b','c','d'],
    'age':[12,13,14,15]
})
df2 = pd.DataFrame({
    'userid':['a','c','e'],
    'money':[123,543,546]
})
print(df1.merge(df2,on='userid',how='outer'))
print('------------')
print(pd.merge(df1,df2,on='userid',how='outer')) # 外连接

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
基于阿里云,构建一个企业web应用上云经典架构,让IT从业者体验企业级架构的实战训练。
相关文章
|
8天前
|
数据采集 数据可视化 数据挖掘
多维数据分析:使用Pandas进行复杂的数据操作和聚合
【4月更文挑战第12天】Pandas是Python的强大数据分析库,提供DataFrame数据结构进行多维数据处理。本文介绍了使用Pandas进行多维数据分析的流程:1) 导入数据(如CSV、Excel);2) 数据预处理,包括缺失值处理和类型转换;3) 数据探索,利用describe()、hist()、plot()等进行统计和可视化;4) 数据操作,如筛选、排序和分组;5) 数据聚合,通过groupby()和agg()进行计算。文中还给出了电商数据分析的案例,展示Pandas在实际应用中的价值。
|
8天前
|
数据挖掘 C语言 索引
数据分析-pandas(三)
在这里,我们将讨论pandas数据结构中常见的许多基本功能
22 0
|
8天前
|
数据挖掘 索引 Python
数据分析-pandas(一)
pandas是Python的一个第三方开源库,是Python数据分析的必备高级工具,Pandas 这个名字来源于面板数据(Panel Data)与数据分析(data analysis)这两个名词的组合。在经济学中,Panel Data 是一个关于多维数据集的术语。Pandas 最初被应用于金融量化交易领域,现在它的应用领域更加广泛,涵盖了农业、工业、交通等许多行业。
40 0
|
8天前
|
数据采集 数据可视化 数据挖掘
利用Python和Pandas库优化数据分析流程
在当今数据驱动的时代,数据分析已成为企业和个人决策的重要依据。Python作为一种强大且易于上手的编程语言,配合Pandas这一功能丰富的数据处理库,极大地简化了数据分析的流程。本文将探讨如何利用Python和Pandas库进行高效的数据清洗、转换、聚合以及可视化,从而优化数据分析的流程,提高数据分析的效率和准确性。
|
8天前
|
SQL 数据采集 数据挖掘
构建高效的Python数据处理流水线:使用Pandas和NumPy优化数据分析任务
在数据科学和分析领域,Python一直是最受欢迎的编程语言之一。本文将介绍如何通过使用Pandas和NumPy库构建高效的数据处理流水线,从而加速数据分析任务的执行。我们将讨论如何优化数据加载、清洗、转换和分析的过程,以及如何利用这些库中的强大功能来提高代码的性能和可维护性。
|
8天前
|
数据可视化 数据挖掘 BI
【Python】—— pandas 数据分析
【Python】—— pandas 数据分析
|
8天前
|
数据采集 数据可视化 数据挖掘
如何利用Python中的Pandas库进行数据分析和可视化
Python的Pandas库是一种功能强大的工具,可以用于数据分析和处理。本文将介绍如何使用Pandas库进行数据分析和可视化,包括数据导入、清洗、转换以及基本的统计分析和图表绘制。通过学习本文,读者将能够掌握利用Python中的Pandas库进行高效数据处理和可视化的技能。
|
8天前
|
数据采集 SQL 数据挖掘
Python数据分析中的Pandas库应用指南
在数据科学和分析领域,Python语言已经成为了一种非常流行的工具。本文将介绍Python中的Pandas库,该库提供了强大的数据结构和数据分析工具,使得数据处理变得更加简单高效。通过详细的示例和应用指南,读者将了解到如何使用Pandas库进行数据加载、清洗、转换和分析,从而提升数据处理的效率和准确性。
|
8天前
|
数据可视化 数据挖掘 C++
数据分析综合案例讲解,一文搞懂Numpy,pandas,matplotlib,seaborn技巧方法
数据分析综合案例讲解,一文搞懂Numpy,pandas,matplotlib,seaborn技巧方法
|
8天前
|
算法 数据挖掘 数据处理
数据分析Pandas之Series,快速上手
数据分析Pandas之Series,快速上手