day7-Pandas数据清洗

1 数据质量的准则

    1. 完整性:单条数据是否存在空值,统计的字段是否完善。
    1. 全面性:观察某一列的全部数值,比如在Excel表中,我们选中一列,可以看到该列的平均值、最大值、最小值。我们可以通过常识来判断该列是否有问题,比如:数据定义、单位标识、数值本身。
    1. 合法性:数据的类型、内容、大小的合法性。比如数据中存在非ASCII字符,性别存在了未知,年龄超过了150岁等。
    1. 唯一性:数据是否存在重复记录,因为数据通常来自不同渠道的汇总,重复的情况是常见的。行数据、列数据都需要是唯一的,比如一个人不能重复记录多次,且一个人的体重也不能在列指标中重复记录多次。

2 处理缺失数据

在数据表或 DataFrame 中有很多识别缺失值的方法。一般情况下可以分为两种:一种方法是通过一个覆盖全局的掩码表示缺失值,另一种方法是用一个标签值(sentinel value)表示缺失值。在掩码方法中,掩码可能是一个与原数组维度相同的完整布尔类型数组,也可能是用一个比特(0 或 1)表示有缺失值的局部状态。

在标签方法中,标签值可能是具体的数据(例如用 -9999 表示缺失的整数),也可能是些极少出现的形式。另外,标签值还可能是更全局的值,比如用 NaN(不是一个数)表示缺失的浮点数

2.1缺失值

  • NonePython对象类型的缺失值
    Pandas 可以使用的第一种缺失值标签是 None,它是一个 Python 单体对象,经常在代码中表示缺失值。由于 None 是一个 Python 对象,所以不能作为任何 NumPy / Pandas 数组类型的缺失值,只能用于 ‘object’ 数组类型(即由 Python 对象构成的数组):
import pandas as pd
import numpy as np
np.array([1, None, 3, 4])

输出:

array([1, None, 3, 4], dtype=object)

这里 dtype=object 表示 NumPy 认为由于这个数组是 Python 对象构成的,因此将其类型判断为 object。虽然这种类型在某些情景中非常有用,对数据的任何操作最终都会在 Python 层面完成,但是在进行常见的快速操作时,这种类型比其他原生类型数组要消耗更多的资源

使用 Python 对象构成的数组就意味着如果你对一个包含 None 的数组进行累计操作,如 sum() 或者 min(),那么通常会出现类型错误:

print(np_arr.sum())  # 报错

在这里插入图片描述
PandasNaNNone的差异

# NaN与 None的差异
ser = pd.Series([1, np.nan, 2, None])
print(ser)
"""
0    1.0
1    NaN
2    2.0
3    NaN
dtype: float64
"""

在这里插入图片描述
Pandas 会将没有标签值的数据类型自动转换为 NA。例如,当我们将整型数组中的一个值设置为 np.nan 时,这个值就会强制转换成浮点数缺失值 NA。

ser2 = pd.Series(range(2), dtype=int)
ser2[0] = None
print(ser2)
"""
0    NaN
1    1.0
dtype: float64
"""

Pandas对不同类型缺失值的转换规则

类型缺失值转换规则NA标签值
floating 浮点型无变化np.nan
object 对象类型无变化None 或 np.nan
integer 整数类型强制转换为 float64np.nan
boolean 布尔类型强制转换为 objectNone 或 np.nan

2.2 处理缺失数据

Pandas 基本上把 None 和 NaN 看成是可以等价交换的缺失值形式。为了完成这种交换过程,Pandas 提供了一些方法来发现、剔除、替换数据结构中的缺失值,主要包括以下几种。

方法说明
isnull()创建一个布尔类型的掩码标签缺失值。
notnull()与 isnull() 操作相反。
dropna()返回一个剔除缺失值的数据。
fillna()返回一个填充了缺失值的数据副本。

判断空值
Pandas 数据结构有两种有效的方法可以发现缺失值:isnull() 和 notnull()。每种方法都返回布尔类型的掩码数据,例如:

ser = pd.Series([1, np.nan, 'hello', None])
print('空值索引:\n', ser.isnull())
print('非空值索引:\n', ser.notnull())
print('空值:\n', ser[ser.isnull()])

在 Series 里使用的 isnull() 和 notnull() 同样适用于DataFrame,产生的结果同样是布尔类型。

剔除缺失值
还有两种很好用的缺失值处理方法,分别是 dropna()(剔除缺失值)和 fillna()(填充缺失值)

# 去除缺失值
print('删除空值:\n', ser.dropna())

而在 DataFrame 上使用它们时需要设置一些参数,例如下面的 DataFrame:

import pandas as pd
import numpy as np

df = pd.DataFrame(data=[[1, np.nan, 2],
                        [2, 3, 5],
                        [np.nan, 4, 6]])

输出:

	0	1	2
0	1.0	NaN	2
1	2.0	3.0	5
2	NaN	4.0	6
"""删除缺失值"""
print('默认删除空行:\n', df.dropna())
默认删除空行:
     0    1  2
1  2.0  3.0  5
# 删除空列
print('默认删除空行:\n', df.dropna())
print('删除空列:\n', df.dropna(axis=1))
默认删除空行:
     0    1  2
1  2.0  3.0  5
删除空列:
   2
0  2
1  5
2  6

但是这么做也会把非缺失值一并剔除,因为可能有时候只需要剔除全部是缺失值的行或列,或者绝大多数是缺失值的行或列。这些需求可以通过设置 how 或 thresh 参数来满足,它们可以设置剔除行或列缺失值的数量阈值。

默认设置是 how=‘any’,也就是说只要有缺失值就剔除整行或整列(通过 axis 设置坐标轴)。你还可以设置 how=‘all’,这样就只会剔除全部是缺失值的行或列了:

print('行列均为空的时候才删除:\n', df.dropna(axis=1, how='all'))

还可以通过 thresh 参数设置保留至少多少个非 NA 值的行,从而实现更加个性化的配置:

print('保留至少2个非 NA 值的行:\n', df.dropna(thresh=2))

并且可以指定列进行剔除

print('指定列删除空值:\n', df.dropna(subset=[1, 2]))
print('指定列删除空值:\n', df.dropna(subset=[1]))

填充缺失值

import pandas as pd
import numpy as np

"""填充缺失值"""

df = pd.DataFrame([[np.nan, 2, np.nan, 0],
                   [3, 4, np.nan, 1],
                   [np.nan, np.nan, np.nan, 5],
                   [np.nan, 3, np.nan, 4]],
                  columns=list("ABCD"))
df

输出:


    A	B	C	D
0	NaN	2.0	NaN	0
1	3.0	4.0	NaN	1
2	NaN	NaN	NaN	5
3	NaN	3.0	NaN	4

我们将用一个单独的值来填充缺失值,例如用 0,也可以用缺失值前面的有效值来从前往后填充(forward-fill)与从后往前填充(back-fill)

print('使用0填充缺失值:\n', df.fillna(0))
print('从前往后填充:\n', df.fillna(method="ffill"))
print('后往前填充:\n', df.fillna(method="bfill"))

输出

使用0填充缺失值:
     A    B    C  D
0  0.0  2.0  0.0  0
1  3.0  4.0  0.0  1
2  0.0  0.0  0.0  5
3  0.0  3.0  0.0  4
从前往后填充:
     A    B   C  D
0  NaN  2.0 NaN  0
1  3.0  4.0 NaN  1
2  3.0  4.0 NaN  5
3  3.0  3.0 NaN  4
后往前填充:
     A    B   C  D
0  3.0  2.0 NaN  0
1  3.0  4.0 NaN  1
2  NaN  3.0 NaN  5
3  NaN  3.0 NaN  4
"""可以修改填充轴"""
print('列填充:\n', df.fillna(method='ffill', axis=1))

输出:

列填充:
     A    B    C    D
0  NaN  2.0  2.0  0.0
1  3.0  4.0  4.0  1.0
2  NaN  NaN  NaN  5.0
3  NaN  3.0  3.0  4.0

并且可以自定义指定列进行填充

values = {"A": 0, "B": 1, "C": 2, "D": 3}
print('指定列进行填充:\n', df.fillna(value=values))

print('只填充一个:\n', df.fillna(value=values, limit=1))

输出:

指定列进行填充:
      A    B    C  D
0  0.0  2.0  2.0  0
1  3.0  4.0  2.0  1
2  0.0  1.0  2.0  5
3  0.0  3.0  2.0  4
只填充一个:
      A    B    C  D
0  0.0  2.0  2.0  0
1  3.0  4.0  NaN  1
2  NaN  1.0  NaN  5
3  NaN  3.0  NaN  4
  • 案例
df=pd.read_excel('./data/水电费.xlsx')
df

在这里插入图片描述

"""删除 门店 这一列有缺失值的行"""
df1 = df.dropna(subset='门店')
df1

在这里插入图片描述

"""将 6月 这一列的缺失值用平均值填充"""
six_month_avg = df['6月'].mean()
df1['6月'] = df1['6月'].fillna(six_month_avg)
df1

输出:
在这里插入图片描述

3 重复数据

方法说明
duplicated()返回布尔型Series表示每行是否为重复行
drop_duplicates()删除重复数据

3.1 处理重复数据

duplicated() 判断重读数据

  • keep 参数
    • first 保留重复数据的第一个
    • last 保留重复数据最后一个
    • False 将所有重复数据全部找出来
  • subset: 指定列查找重复数据
import numpy as np
import pandas as pd

"""重复行"""
df = pd.DataFrame({
    'brand': ['Yum Yum', 'Yum Yum', 'Indomie', 'Indomie', 'Indomie', 'Indomie'],
    'style': ['cup', 'cup', 'cup', 'pack', 'pack', 'pack'],
    'rating': [4, 4, 3.5, 15, 5, 5]
})
df

输出:

	brand	style	rating
0	Yum Yum	cup		4.0
1	Yum Yum	cup		4.0
2	Indomie	cup		3.5
3	Indomie	pack	15.0
4	Indomie	pack	5.0
5	Indomie	pack	5.0
# 判断重复行,默认保留第一个
print(df.duplicated())
# 判断重复行,保留最后一个
print('保留最后一个:\n', df.duplicated(keep='last'))

输出:

0    False
1     True
2    False
3    False
4    False
5     True
dtype: bool

保留最后一个:
 0     True
1    False
2    False
3    False
4     True
5    False
dtype: bool
# 所有的重复行全部标注出来
print('全部标注:\n', df.duplicated(keep=False))

# 获取指定列的重复行
print('指定列:\n', df.duplicated(subset=['brand']))
全部标注:
 0     True
1     True
2    False
3    False
4     True
5     True
dtype: bool
指定列:
 0    False
1     True
2    False
3     True
4     True
5     True
dtype: bool

3.2 过滤重复行

drop_duplicates() 删除重复数据的方法
参数和 duplicated() 参数一模一样

  • drop_duplicates()
    • 默认判断全部列
    • 可指定按某些列判断
df.drop_duplicates()

输出:

	brand	style	rating
0	Yum Yum	cup	4.0
2	Indomie	cup	3.5
3	Indomie	pack	15.0
4	Indomie	pack	5.0
  • 案例
df = pd.read_csv('./data/guazi.csv')
df

在这里插入图片描述

df.duplicated()

在这里插入图片描述

df.drop_duplicates()

在这里插入图片描述

4 数据替换

4.1 替换值

df = pd.DataFrame({'A': [0, 1, 2, 3, 4],
                   'B': [5, 6, 7, 8, 9],
                   'C': ['a', 'b', 'c', 'd', 'e']})

df

输出:


	A	B	C
0	0	5	a
1	1	6	b
2	2	7	c
3	3	8	d
4	4	9	e
# 可以指定一个值进行替换
df.replace(0, 100)  

输出:

	A	B	C
0	100	5	a
1	1	6	b
2	2	7	c
3	3	8	d
4	4	9	e
4.1.1列表转换
df.replace([0, 5, 'b'], 200)  # 将列表中的值替换成 200  多对一
  
df.replace([0, 5, 'b'], [100, 200, 300])  # 多对多, 需要一一对应
	A	B	C
0	100	200	a
1	1	6	300
2	2	7	c
3	3	8	d
4	4	9	e

字典转换

"""字典替换"""
# df.replace({0: 10, 1:20, 2:30})  # 指定值进行替换, 根据键替换值

df.replace({'A': 0, 'B':5}, 100)  # 可以按照列指定数据, 进行替换

df.replace({'A': {0: 10, 1:20, 2:30}})   # 只替换A这一列

输出

	A	B	C
0	10	5	a
1	20	6	b
2	30	7	c
3	3	8	d
4	4	9	e
4.1.2正则替换
df = pd.DataFrame({'A': ['bat', 'foo', 'bait'],
                   'B': ['abc', 'bar', 'xyz']})
df

输出:

	A	B
0	bat	abc
1	foo	bar
2	bait	xyz
# 正则表达式匹配的数据, 替换成指定的字符串
# regex 正则表达式规则, value 匹配的数据需要替换的内容
df.replace(regex='^ba.$', value='new')

输出

	A	B
0	new	abc
1	foo	new
2	bait	xyz
# 可以指定字典结合正则进行替换
df.replace(regex={'^ba.$': 'new', 'foo': 'xyz'})

输出

	A	B
0	new	abc
1	xyz	new
2	bait	xyz
# 多个正则, 整体替换
df.replace(regex=['^ba.$', 'foo'], value='111')

输出

	A	B
0	111	abc
1	111	111
2	bait	xyz
  • 案例
df = pd.read_csv('./data/淘宝T恤.csv', engine='python', encoding='gbk')
df

在这里插入图片描述

df['location'].replace(regex='.*? ', value='')  #广东 广州,匹配空格后面的们就是城市了

在这里插入图片描述

4.2 数据转换

  • map函数替换
s = pd.Series(['cat', 'dog', np.nan, 'rebbit'])
s
0       cat
1       dog
2       NaN
3    rebbit
dtype: object
# 可以指定字典进行替换, 但是没有指定的内容会当做缺失值处理
s.map({'cat': 'kitten', 'dog': 'bobby'})

输出:

0    kitten
1     bobby
2       NaN
3       NaN
dtype: object
def func(temp):
    print('传入的值:', temp)
    return f'I am a {temp}'

# 在替换的时候 None 会当做字符串处理
# map指定函数替换, 会将Series中每一个数据传递到函数的参数中处理, 一个一个传递进去

s.map(func)
传入的值: cat
传入的值: dog
传入的值: nan
传入的值: rebbit
0       I am a cat
1       I am a dog
2       I am a nan
3    I am a rebbit
dtype: object
s.map(func, na_action='ignore')  # na_action='ignore' 忽略缺失值操作数据
传入的值: cat
传入的值: dog
传入的值: rebbit
0       I am a cat
1       I am a dog
2              NaN
3    I am a rebbit
dtype: object

apply
apply 将函数应用到列或行上

  • apply(func, axis=0)
    • func:自定义函数
    • axis=0:默认是列,axis=1为行进行运算
  • 定义一个对列,最大值-最小值的函数
df = pd.DataFrame(data=[[4, 9],
                        [4, 9],
                        [4, 9]],
                  columns=['A', 'B'])

df

输出:

	A	B
0	4	9
1	4	9
2	4	9
#平方化
def funx(x):
    print("传进来的值:\n", x)
    return x * x
# apply 默认操作整列
df.apply(funx)
传进来的值:
 0    4
1    4
2    4
Name: A, dtype: int64
传进来的值:
 0    9
1    9
2    9
Name: B, dtype: int64
	A	B
0	16	81
1	16	81
2	16	81

在这里插入图片描述

def funx_sum(x):
    return np.sum(x)

df.apply(funx_sum)  #默认操作轴axis=0,按列操作

输出:

A    12
B    27
dtype: int64
df.apply(funx_sum, axis=1) 
0    13
1    13
2    13
dtype: int64

applymap
applymap 将函数应用到每个数据

"""批量操作数据 针对每一个元素"""
df = pd.DataFrame([[1, 2.12], [3.356, 4.567]])
print(df)

print(df.applymap(lambda x: '%.2f' % x))

输出:

       0      1
0  1.000  2.120
1  3.356  4.567
      0     1
0  1.00  2.12
1  3.36  4.57
- Series  --> map函数操作
- DataFrame  --> apply 可以操作行或者列
- DataFrame每个元素  -->  applymap  replace
  • 案例
df = pd.read_excel('./data/淘宝T恤评论.xlsx')
df

在这里插入图片描述

df1 = df[['标题', 'card-act']]
df1

在这里插入图片描述

# 获取转发次数,删除"转发"
def func(x):
    result = x.split()
    # print(result)   //['转发','8']   ['转发']   都是字符串类型
    if len(result) == 1:
        return 1
    else:
        return int(result[1])


df1['card-act'] = df1['card-act'].map(func)
df1
#运行一次之后再次运行需要重启内核

在这里插入图片描述

# 评论也是如此
for arg in ['card-act', 'card-act1']:
    df[arg] = df[arg].map(func)
df

在这里插入图片描述

5 字符串操作

5.1字符串方法

在这里插入图片描述
在这里插入图片描述

5.2 正则表达式方法

在这里插入图片描述

5.3 Pandas字符串函数

在这里插入图片描述

  • 案例
df = pd.read_csv('./data/taobao_data.csv', encoding='gbk')
df

在这里插入图片描述

df = df[ ['标题', 'deal-cnt']]
df

在这里插入图片描述

#字符串替换
df['deal-cnt'] = df['deal-cnt'].str.strip('人收货')  # 字符串替换, 一定要转对象


def func(x):
    if '万+' in x:
        return float(x.replace('万+', '')) * 10000
    
    elif '+' in x:
        return float(x.replace('+', '')) 
    
    else:
        return float(x)

df['deal-cnt'] = df['deal-cnt'].map(func)
df

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值