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

2023-11-30 21:20

本文主要是介绍一文过pandas入门(中篇)——才疏学浅的莫笑天,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本篇核心内容为数据清洗。

数据清洗

数据工作的步骤应该为:

  1. 数据获取
  2. 数据清洗
  3. 数据分析
  4. 数据可视化与建模
    因此,上一篇博文中,本人说过,下一篇博文会讲一下数据分析中重要的一步
    我们要知道,数据清洗本着为下一步数据分析服务的目的进行,因此,数据处理要根据数据分析确定它是否需要处理,需要怎样的处理,才能适应接下来的分析工作和挖掘工作。

整体分为几个不同的步骤来看。

import pandas as pd
import numpy as np

一. 缺失数据的处理

整体的处理方法在理论上我们可以采用填补或者丢弃。选择哪种依情况而定。总体工作对于pandas来说,就利用四个方法:

  1. fillna():填充
  2. dropna():根据条件筛选过滤
  3. isnull():判断是否为空
  4. notnull():判断是否不为空

如上四个函数,加上我们其他的语法,逻辑等,基本可以完成这一步工作。如下做演示,这几个方法不需要特别讲解

df = pd.DataFrame([np.random.rand(3),np.random.rand(3),np.random.rand(3)],columns=['A','B','C'])
df
ABC
00.9025980.5983100.169824
10.4253680.8059500.677491
20.8303660.3052270.487216
df['A'][0] = np.NAN
print(df)
df.fillna(1)
          A         B         C
0       NaN  0.598310  0.169824
1  0.425368  0.805950  0.677491
2  0.830366  0.305227  0.487216
ABC
01.0000000.5983100.169824
10.4253680.8059500.677491
20.8303660.3052270.487216
df['A'][0] = np.NAN
print(df)
df.dropna()
          A         B         C
0       NaN  0.598310  0.169824
1  0.425368  0.805950  0.677491
2  0.830366  0.305227  0.487216
ABC
10.4253680.8059500.677491
20.8303660.3052270.487216
# 根据参数确定丢失行或列
df['A'][0] = np.NAN
print(df)
df.dropna(axis=1)
          A         B         C
0       NaN  0.598310  0.169824
1  0.425368  0.805950  0.677491
2  0.830366  0.305227  0.487216
BC
00.5983100.169824
10.8059500.677491
20.3052270.487216
# 获取bool值对应的dataframe。
bool_df_t = df.isnull()
bool_df_t
ABC
0TrueFalseFalse
1FalseFalseFalse
2FalseFalseFalse
# 与上者相反
bool_df = df.notnull()
bool_df
ABC
0FalseTrueTrue
1TrueTrueTrue
2TrueTrueTrue

当然它也可以完成类似于numpyarray中的操作,不过没啥意义。

print(df[bool_df_t])
print(df[bool_df])
    A   B   C
0 NaN NaN NaN
1 NaN NaN NaN
2 NaN NaN NaNA         B         C
0       NaN  0.598310  0.169824
1  0.425368  0.805950  0.677491
2  0.830366  0.305227  0.487216

二. 重复值的处理

考虑到某些数据不符合我们的分析要求,或者输入建模的问题,需要在某种情况下对数据进行重复值的处理

# 构建包含重复值的数据
df_obj = pd.DataFrame({'data1' : ['a'] * 4 + ['b'] * 4,'data2' : np.random.randint(0, 4, 8)})
print(df_obj)
## df.duplicated():判断重复数据,默认是判断全部列,可指定列数判断。我们可以根据得出的结果分析,方法会记录第一次出现的数据,标记为false,但
## 之后再出现的数据就会被标记为True,表示重复。
print(df_obj.duplicated())
  data1  data2
0     a      1
1     a      2
2     a      2
3     a      0
4     b      1
5     b      1
6     b      1
7     b      1
0    False
1    False
2     True
3    False
4    False
5     True
6     True
7     True
dtype: bool
## 我们也可以利用它判断某一列。
print(df_obj.duplicated('data2'))
0    False
1    False
2     True
3    False
4     True
5     True
6     True
7     True
dtype: bool

判断之后,可以利用drop_duplicates()方法删除重复的行。

# 它可以删除掉已经重复的数据,保留第一次出现的数据。
df_obj.drop_duplicates()
data1data2
0a1
1a2
3a0
4b1

三. 数据格式转化

考虑到部分数据格式的存在可能不符合后期数据分析的标准,或者不适合作为模型的输入,我们要对某些数据做对应的处理。

  1. 利用函数进行映射。
  2. 直接指定值进行替换处理。
# 生成随机数据
ser_obj = pd.Series(np.random.randint(0,10,10))
ser_obj
0    0
1    0
2    7
3    3
4    0
5    8
6    6
7    7
8    8
9    9
dtype: int32
# 进行函数映射,利用lamdba表达式,map函数与numpy中的applymap相似,与python基础语法的map也相似。可以认为相同
ser_obj.map(lambda x : x ** 2)
0     0
1     0
2    49
3     9
4     0
5    64
6    36
7    49
8    64
9    81
dtype: int64
# 进行值的替换,replace方法
# 生成一个随机的series
data = pd.Series(np.random.randint(0,100,10))
print(data)
0    73
1    18
2    48
3    27
4     1
5    60
6    59
7    38
8    66
9    53
dtype: int32
# 单一替换
data = data.replace(73,100)
data
0    100
1     18
2     48
3     27
4      1
5     60
6     59
7     38
8     66
9     53
dtype: int32
# 多对对替换
data = data.replace([100,18],[-1,-1])
data
0    -1
1    -1
2    48
3    27
4     1
5    60
6    59
7    38
8    66
9    53
dtype: int64

字符串操作,可直接继承python基本语法的字符串操作,这里不在浪费时间。

四. 数据合并

根据不同的条件将数据进行联合。主要使用的方法是pd.merge

pd.merge:(left, right, how=‘inner’,on=None,left_on=None, right_on=None )

left:合并时左边的DataFrame

right:合并时右边的DataFrame

how:合并的方式,默认’inner’, ‘outer’, ‘left’, ‘right’

on:需要合并的列名,必须两边都有的列名,并以 left 和 right 中的列名的交集作为连接键

left_on: left Dataframe中用作连接键的列

right_on: right Dataframe中用作连接键的列

四种连接方式非常重要,它们分别为内连接,全连接,左连接,右连接。

  1. 内连接:根据指定键的交集进行连接。
  2. 外连接:根据指定键的并集进行连接。
  3. 左连接:根据指定left的dataframe键进行连接。
  4. 右连接:根据指定right的dataframe的键进行连接。
import pandas as pd
import numpy as npleft = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],'A': ['A0', 'A1', 'A2', 'A3'],'B': ['B0', 'B1', 'B2', 'B3']})right = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],'C': ['C0', 'C1', 'C2', 'C3'],'D': ['D0', 'D1', 'D2', 'D3']})
left
keyAB
0K0A0B0
1K1A1B1
2K2A2B2
3K3A3B3
right
keyCD
0K0C0D0
1K1C1D1
2K2C2D2
3K3C3D3
pd.merge(left,right,on='key') #指定连接键key
keyABCD
0K0A0B0C0D0
1K1A1B1C1D1
2K2A2B2C2D2
3K3A3B3C3D3
## 可以看到left和right数据都有key键,他们的值都有k0,k1,k2,k3,进行连接后,指定为key后,他们连接起来,数据拼接没有丢失任何数据。
left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],'key2': ['K0', 'K1', 'K0', 'K1'],'A': ['A0', 'A1', 'A2', 'A3'],'B': ['B0', 'B1', 'B2', 'B3']})right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],'key2': ['K0', 'K0', 'K0', 'K0'],'C': ['C0', 'C1', 'C2', 'C3'],'D': ['D0', 'D1', 'D2', 'D3']})
left
key1key2AB
0K0K0A0B0
1K0K1A1B1
2K1K0A2B2
3K2K1A3B3
right
key1key2CD
0K0K0C0D0
1K1K0C1D1
2K1K0C2D2
3K2K0C3D3
pd.merge(left,right,on=['key1','key2']) #指定多个键,进行合并
key1key2ABCD
0K0K0A0B0C0D0
1K1K0A2B2C1D1
2K1K0A2B2C2D2

look,如上所示,内连接的方法是连接交集,对于k1 k0这个序列,在right中,显然存在两组数据,而left中只存在一组数据,根据交集来看,这两组数据与那一组数据都属于交集,因此,拼接为两组数据。那如果是left中存在两组呢,我们来看看结果。

left = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],'key2': ['K0', 'K0', 'K0', 'K1'],'A': ['A0', 'A1', 'A2', 'A3'],'B': ['B0', 'B1', 'B2', 'B3']})right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],'key2': ['K0', 'K0', 'K0', 'K0'],'C': ['C0', 'C1', 'C2', 'C3'],'D': ['D0', 'D1', 'D2', 'D3']})
print(pd.merge(left,right,on=['key1','key2']))
  key1 key2   A   B   C   D
0   K0   K0  A0  B0  C0  D0
1   K1   K0  A1  B1  C1  D1
2   K1   K0  A1  B1  C2  D2
3   K1   K0  A2  B2  C1  D1
4   K1   K0  A2  B2  C2  D2

我们来思考一下合并的规则,对于如上数据,我们最终得到5条数据,实际上left和right匹配的数据仅仅只有,一组k0 k0,两组k1 k0罢了,但是这两组k1 k0却进行了交集运算,将数据合并为四组,这种交集运算其实不难理解,但是初次接触也需要思考这其实是数据库交集的计算。可以从如下例子入手。
在这里插入图片描述

left = pd.DataFrame({'key':['c','d','c'],'A':['a','b','e'],'B':['a','b','e']},
)
right = pd.DataFrame({'key':['c','d','c'],'C':['a','b','c'],'D':['a','b','c']},
)
left
keyAB
0caa
1dbb
2cee
right
keyCD
0caa
1dbb
2ccc
pd.merge(left,right,on=['key'])
keyABCD
0caaaa
1caacc
2ceeaa
3ceecc
4dbbbb
left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],'key2': ['K0', 'K1', 'K0', 'K1'],'A': ['A0', 'A1', 'A2', 'A3'],'B': ['B0', 'B1', 'B2', 'B3']})
right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],'key2': ['K0', 'K0', 'K0', 'K0'],'C': ['C0', 'C1', 'C2', 'C3'],'D': ['D0', 'D1', 'D2', 'D3']})
print(pd.merge(left, right, how='left', on=['key1', 'key2']))## 匹配left数据框内有的所有键对,right没有则不匹配。
  key1 key2    A    B   C   D
0   K0   K0   A0   B0  C0  D0
1   K1   K0   A2   B2  C1  D1
2   K1   K0   A2   B2  C2  D2
3   K2   K0  NaN  NaN  C3  D3
print(pd.merge(left, right, how='right', on=['key1', 'key2']))## 匹配right数据框内所有的键对,left没有则不匹配。
  key1 key2    A    B   C   D
0   K0   K0   A0   B0  C0  D0
1   K1   K0   A2   B2  C1  D1
2   K1   K0   A2   B2  C2  D2
3   K2   K0  NaN  NaN  C3  D3

外连接,所有值,不存在则用na填充(并集)

left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],'key2': ['K0', 'K1', 'K0', 'K1'],'A': ['A0', 'A1', 'A2', 'A3'],'B': ['B0', 'B1', 'B2', 'B3']})
right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],'key2': ['K0', 'K0', 'K0', 'K0'],'C': ['C0', 'C1', 'C2', 'C3'],'D': ['D0', 'D1', 'D2', 'D3']})
print(pd.merge(left,right,how='outer',on=['key1','key2']))
  key1 key2    A    B    C    D
0   K0   K0   A0   B0   C0   D0
1   K0   K1   A1   B1  NaN  NaN
2   K1   K0   A2   B2   C1   D1
3   K1   K0   A2   B2   C2   D2
4   K2   K1   A3   B3  NaN  NaN
5   K2   K0  NaN  NaN   C3   D3

处理列名重复数据

# 处理重复列名
df_obj1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],'data' : np.random.randint(0,10,7)})
df_obj2 = pd.DataFrame({'key': ['a', 'b', 'd'],'data' : np.random.randint(0,10,3)})
df_obj1
keydata
0b4
1b5
2a3
3c0
4a4
5a5
6b4
df_obj2
keydata
0a8
1b7
2d8
print(pd.merge(df_obj1, df_obj2, on='key', suffixes=('_left', '_right')))
  key  data_left  data_right
0   b          4           7
1   b          5           7
2   b          4           7
3   a          3           8
4   a          4           8
5   a          5           8
# 按索引连接
df_obj1 = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],'data1' : np.random.randint(0,10,7)})
df_obj2 = pd.DataFrame({'data2' : np.random.randint(0,10,3)}, index=['a', 'b', 'd'])
  key  data1  data2
0   b      4      8
1   b      0      8
6   b      1      8
2   a      6      1
4   a      4      1
5   a      2      1
df_obj1
keydata1
0b4
1b0
2a6
3c1
4a4
5a2
6b1
df_obj2
data2
a1
b8
d8
# 指以left的键为主键,按索引连接。
pd.merge(df_obj1, df_obj2, left_on='key', right_index=True)
keydata1data2
0b48
1b08
6b18
2a61
4a41
5a21

pd.concat()方法

类似于np.concat,连接数组,这里则是连接dataframe。

df1 = pd.DataFrame(np.arange(6).reshape(3,2),index=list('abc'),columns=['one','two'])df2 = pd.DataFrame(np.arange(4).reshape(2,2)+5,index=list('ac'),columns=['three','four'])
df1
onetwo
a01
b23
c45
df2
threefour
a56
c78
## 默认连接方式为外连接,也就是所谓的并集。
pd.concat([df1,df2])
onetwothreefour
a0.01.0NaNNaN
b2.03.0NaNNaN
c4.05.0NaNNaN
aNaNNaN5.06.0
cNaNNaN7.08.0
## 当然亦如之前的方法,都可以指定参数axis,这便类似于上面的操作。merge()方法
pd.concat([df1,df2],axis=1)
onetwothreefour
a015.06.0
b23NaNNaN
c457.08.0
## 同样也可以指定连接方式 比如'inner'内连接(交集)
pd.concat([df1,df2],axis=1,join='inner')
onetwothreefour
a0156
c4578

数据的重塑

# 1. 将列索引转化为行索引:stack方法
df_obj = pd.DataFrame(np.random.randint(0,10, (5,2)), columns=['data1', 'data2'])stacked = df_obj.stack()
   data1  data2
0      5      3
1      7      4
2      5      7
3      7      2
4      9      5
0  data1    5data2    3
1  data1    7data2    4
2  data1    5data2    7
3  data1    7data2    2
4  data1    9data2    5
dtype: int32
df_obj
data1data2
053
174
257
372
495
stacked
0  data1    5data2    3
1  data1    7data2    4
2  data1    5data2    7
3  data1    7data2    2
4  data1    9data2    5
dtype: int32

如上,数据索引变成了层级索引。

print(type(df_obj))
# 可以看到数据格式发生了变化,从dataframe转化到了series
print(type(stacked))
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.series.Series'>
# 2. 将层级索引展为行索引unstack()方法
stacked.unstack()
data1data2
053
174
257
372
495

整体再来整理一下。

为什么要进行数据清洗?是为了后续的数据分析,建模等操作的方便执行。
数据清洗在数据分析工作的哪一步?在数据分析工作前,为数据分析,模型服务。
数据清洗的流程?
分为几大类:

1. 进行缺失值处理
2. 进行重复值处理
3. 进行数据格式转化
4. 进行数据合并

ok,今天到这里了,本人不准备专门为时间序列结构出一篇博客,所以打算直接将它渗透到后期的实战中,在实战之前还需要补充一些统计学的知识,感谢大家的关注。同学习python的同学可以博主微信,有问题直接交流。

在这里插入图片描述

这篇关于一文过pandas入门(中篇)——才疏学浅的莫笑天的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/438600

相关文章

一文详解SpringBoot中控制器的动态注册与卸载

《一文详解SpringBoot中控制器的动态注册与卸载》在项目开发中,通过动态注册和卸载控制器功能,可以根据业务场景和项目需要实现功能的动态增加、删除,提高系统的灵活性和可扩展性,下面我们就来看看Sp... 目录项目结构1. 创建 Spring Boot 启动类2. 创建一个测试控制器3. 创建动态控制器注

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

一文详解Git中分支本地和远程删除的方法

《一文详解Git中分支本地和远程删除的方法》在使用Git进行版本控制的过程中,我们会创建多个分支来进行不同功能的开发,这就容易涉及到如何正确地删除本地分支和远程分支,下面我们就来看看相关的实现方法吧... 目录技术背景实现步骤删除本地分支删除远程www.chinasem.cn分支同步删除信息到其他机器示例步骤

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

一文详解Java Stream的sorted自定义排序

《一文详解JavaStream的sorted自定义排序》Javastream中的sorted方法是用于对流中的元素进行排序的方法,它可以接受一个comparator参数,用于指定排序规则,sorte... 目录一、sorted 操作的基础原理二、自定义排序的实现方式1. Comparator 接口的 Lam

从入门到精通MySQL 数据库索引(实战案例)

《从入门到精通MySQL数据库索引(实战案例)》索引是数据库的目录,提升查询速度,主要类型包括BTree、Hash、全文、空间索引,需根据场景选择,建议用于高频查询、关联字段、排序等,避免重复率高或... 目录一、索引是什么?能干嘛?核心作用:二、索引的 4 种主要类型(附通俗例子)1. BTree 索引(

Redis 配置文件使用建议redis.conf 从入门到实战

《Redis配置文件使用建议redis.conf从入门到实战》Redis配置方式包括配置文件、命令行参数、运行时CONFIG命令,支持动态修改参数及持久化,常用项涉及端口、绑定、内存策略等,版本8... 目录一、Redis.conf 是什么?二、命令行方式传参(适用于测试)三、运行时动态修改配置(不重启服务

MySQL DQL从入门到精通

《MySQLDQL从入门到精通》通过DQL,我们可以从数据库中检索出所需的数据,进行各种复杂的数据分析和处理,本文将深入探讨MySQLDQL的各个方面,帮助你全面掌握这一重要技能,感兴趣的朋友跟随小... 目录一、DQL 基础:SELECT 语句入门二、数据过滤:WHERE 子句的使用三、结果排序:ORDE

一文深入详解Python的secrets模块

《一文深入详解Python的secrets模块》在构建涉及用户身份认证、权限管理、加密通信等系统时,开发者最不能忽视的一个问题就是“安全性”,Python在3.6版本中引入了专门面向安全用途的secr... 目录引言一、背景与动机:为什么需要 secrets 模块?二、secrets 模块的核心功能1. 基