数据清洗与准备(3)

2023-02-23 21:17:38 浏览数 (2)

1 处理缺失值

(1)过滤缺失值(点此跳转)

(2)补全缺失值(点此跳转)

2 数据转换

(1)删除重复值(点此跳转)

(2)使用函数或映射进行数据转换(点此跳转)

(3)替代值(点此跳转)

(4)重命名轴索引

重命名轴索引可以在不生成新的数据的情况下修改轴,一个有用的方法是rename,示例如下:

代码语言:javascript复制
import pandas as pd
import numpy as np
data = pd.DataFrame(np.arange(12).reshape((3, 4)),
                   index = ['Apple', 'Orange', 'Banana'],
                   columns = ['Price', 'Rest', 'Sell', 'Weight'])
print(data)
print(data.rename(index = str.upper, columns = str.upper)) #将轴都变为大写
-----结果-----
data:
          Price  Rest  Sell  Weight
Apple       0     1     2       3
Orange      4     5     6       7
Banana      8     9    10      11
rename:
      PRICE  REST  SELL  WEIGHT
APPLE    0    1      2      3
ORANGE    4    5      6      7
BANANA    8    9      10      11

同时,rename也可以结合字典对象使用,用于修改轴索引:

代码语言:javascript复制
data.rename(index={'Apple': 'Grape'}, columns = {'Weight': 'Test'}) #将Apple转成Grape,将Weight转成Test
      Price  Rest  Sell  Test
Grape    0    1     2    3
Orange   4    5     6    7
Banana   8    9    10   11

以上修改都是生成一个对象,如果想要修改原有数据集,仅需在函数加一个参数inplace=True即可。

(5)离散化和分箱

连续值经常需要离散化,或者分成若干组进行分析。例如有一组年龄数据,需要分成若干组:

代码语言:javascript复制
ages = [20, 31, 22, 34, 61, 50, 43, 27, 23, 60, 46, 33]

需要将年龄分为18-25、26-35、36-60以及61以上3组,实现这个可以使用pandas的cut

代码语言:javascript复制
bins = [18, 25, 35, 60, 100]
cats = pd.cut(ages, bins)
cats
-----结果-----
[(18, 25], (25, 35], (18, 25], (25, 35], (60, 100], ..., (25, 35], (18, 25], (35, 60], (35, 60], (25, 35]]
Length: 12
Categories (4, interval[int64]): [(18, 25] < (25, 35] < (35, 60] < (60, 100]]

返回了一个Categories对象,可以通过pandas的value_counts方法计算每一个分组的数量:

代码语言:javascript复制
pd.value_counts(cats) #计算每一个分组的数量
-----结果-----
(35, 60]     4
(25, 35]     4
(18, 25]     3
(60, 100]    1

区间的符号与数学上一致,可以通过传递right=False来改变那一边是封闭的;也可以传入labels选项自定义分组名称:

代码语言:javascript复制
names = ['Youth', 'YoungAdult', 'MiddleAged', 'Senior']
cats = pd.cut(ages, bins, right=True,labels = names)
pd.value_counts(cats)
-----结果-----
[[18, 25), [25, 35), [18, 25), [25, 35), [60, 100), ..., [25, 35), [18, 25), [60, 100), [35, 60), [25, 35)]
Length: 12
Categories (4, interval[int64]): [[18, 25) < [25, 35) < [35, 60) < [60, 100)]
MiddleAged    4
YoungAdult    4
Youth         3
Senior        1

如果给cut传入一个整数的箱边,pandas将会根据最小值和最大值计算出等长的箱:

代码语言:javascript复制
data = np.random.rand(20)
pd.cut(data, 4, precision = 2) #将数据分成4份,注意不是四等份,precison保留两位小数
[(0.77, 0.99], (0.77, 0.99], (0.13, 0.34], (0.77, 0.99], (0.56, 0.77], ..., (0.56, 0.77], (0.56, 0.77], (0.77, 0.99], (0.77, 0.99], (0.13, 0.34]]
Length: 20
Categories (4, interval[float64]): [(0.13, 0.34] < (0.34, 0.56] < (0.56, 0.77] < (0.77, 0.99]]

qcut它是依据样本分位数分箱;使用cut通常不会使每一组有相同数量的数据点,而qcut基于样本分位数分箱,可以保证每个组的数量相等:

代码语言:javascript复制
data = np.random.rand(1000) #从-1~1随机取1000个数
cats = pd.qcut(data, 4, precision = 2) #等分为4份
pd.value_counts(cats)
-----结果-----
(0.75, 1.0]        250
(0.51, 0.75]       250
(0.26, 0.51]       250
(-0.0083, 0.26]    250

也可以传入自定义分位数(0-1之间):

代码语言:javascript复制
data = np.random.randn(1000)
cats = pd.qcut(data, [0, 0.1, 0.3, 0.7, 0.95, 1], precision = 2)
pd.value_counts(cats)
-----结果-----
(0.33, 0.7]         400
(0.7, 0.95]         250
(0.11, 0.33]        200
(-0.00922, 0.11]    100
(0.95, 1.0]          50

(6)检测和过滤异常值

过滤和转换异常值是数组操作经常遇到的事,以一个例子为例:

代码语言:javascript复制
df = pd.DataFrame(np.random.rand(1000, 4)) #正态分布,取四次样,每次1000个数
df.describe() #输出描述性信息

假如要找出有值大于3或小于-3的行,可以使用any方法:

代码语言:javascript复制
df[(np.abs(df) > 3).any(1)]

以上就是数据清洗和准备的大致内容,高效的数据准备工作可以使我们将更多的时间用于数据分析而不是准备数据,从而提升工作效率。已经介绍了多个处理工具,但仍然不太全面。在下一章将会介绍pandas的数据连接和联合等功能。

0 人点赞