利用Python进行数据分析(五):数据清洗和准备

利用Python进行数据分析(五):数据清洗和准备

一、处理缺失数据

pandas对象的所有描述性统计默认都不包括缺失数据。

1、检测缺失数据

比如新建一个Series,用isnull函数检测是否为缺失值,对于数值数据,pandas使用浮点值NaN(Not a Number)表示缺失数据。

import numpy as np
import pandas as pd
string_data = pd.Series(['aar', 'art', np.nan, 'avo'])
string_data
0    aar
1    art
2    NaN
3    avo
dtype: object
string_data.isnull()
0    False
1    False
2     True
3    False
dtype: bool

当进行数据清洗以进行分析时,最好直接对缺失数据进行分析,以判断数据采集的问题或缺失数据可能导致的偏差。
Python内置的None值在对象数组中也可以作为NA:

string_data[0]=None
string_data
0    None
1     art
2     NaN
3     avo
dtype: object
string_data.isnull()
0     True
1    False
2     True
3    False
dtype: bool

处理缺失数据的函数

利用Python进行数据分析(五):数据清洗和准备

2、过滤缺失数据

Series
对于一个Series,dropna返回一个仅含非空数据和索引值的Series:

string_data.dropna()
1    art
3    avo
dtype: object

from numpy import nan as na
data = pd.Series([1,na,3.5,na,7])
data
0    1.0
1    NaN
2    3.5
3    NaN
4    7.0
dtype: float64
data.dropna()
0    1.0
2    3.5
4    7.0
dtype: float64
data[data.notnull()]
0    1.0
2    3.5
4    7.0
dtype: float64

data.dropna()等价于data[data.notnull()]

DataFrame
而对于DataFrame对象,事情就有点复杂了。你可能希望丢弃全NA或含有NA的行或列。dropna默认丢弃任何含有缺失值的行:

data1 = pd.DataFrame([[1,2,3],[1,na,na],[na,na,na],[na,6.5,3]])
data1
     0    1    2
0  1.0  2.0  3.0
1  1.0  NaN  NaN
2  NaN  NaN  NaN
3  NaN  6.5  3.0
cleaned = data1.dropna()
cleaned
     0    1    2
0  1.0  2.0  3.0

传入how=’all’将只丢弃全为NA的那些行:

data1.dropna(how='all')
     0    1    2
0  1.0  2.0  3.0
1  1.0  NaN  NaN
3  NaN  6.5  3.0

用这种方式丢弃列,只需传入axis=1即可:

data1.dropna(axis=1,how='all')
     0    1    2
0  1.0  2.0  3.0
1  1.0  NaN  NaN
2  NaN  NaN  NaN
3  NaN  6.5  3.0

时间序列
假设你只想留下一部分观测数据,可以用thresh参数实现此目的:

df = pd.DataFrame(np.random.randn(7,3))
df.iloc[:4,1]=na
df
          0         1         2
0 -0.656451       NaN -0.961644
1  0.139871       NaN -0.390374
2  0.264801       NaN -0.399654
3 -0.242247       NaN  0.871069
4  0.975986 -0.763189  1.567743
5 -1.128100 -0.355459 -0.050403
6 -0.614838  0.359948  0.173833
df.iloc[:2,2]=na
df
          0         1         2
0 -0.656451       NaN       NaN
1  0.139871       NaN       NaN
2  0.264801       NaN -0.399654
3 -0.242247       NaN  0.871069
4  0.975986 -0.763189  1.567743
5 -1.128100 -0.355459 -0.050403
6 -0.614838  0.359948  0.173833
df.dropna()
          0         1         2
4  0.975986 -0.763189  1.567743
5 -1.128100 -0.355459 -0.050403
6 -0.614838  0.359948  0.173833
df.dropna(thresh=2)
          0         1         2
2  0.264801       NaN -0.399654
3 -0.242247       NaN  0.871069
4  0.975986 -0.763189  1.567743
5 -1.128100 -0.355459 -0.050403
6 -0.614838  0.359948  0.173833

填充缺失数据

df.fillna(0)
          0         1         2
0 -0.656451  0.000000  0.000000
1  0.139871  0.000000  0.000000
2  0.264801  0.000000 -0.399654
3 -0.242247  0.000000  0.871069
4  0.975986 -0.763189  1.567743
5 -1.128100 -0.355459 -0.050403
6 -0.614838  0.359948  0.173833

若是通过一个字典调用fillna,就可以实现对不同的列填充不同的值:

df.fillna({1:0.5,2:2.5})
          0         1         2
0 -0.656451  0.500000  2.500000
1  0.139871  0.500000  2.500000
2  0.264801  0.500000 -0.399654
3 -0.242247  0.500000  0.871069
4  0.975986 -0.763189  1.567743
5 -1.128100 -0.355459 -0.050403
6 -0.614838  0.359948  0.173833

fillna默认会返回新对象,但也可以对现有对象进行就地修改:

_=df.fillna(0,inplace=True)
df
          0         1         2
0 -0.656451  0.000000  0.000000
1  0.139871  0.000000  0.000000
2  0.264801  0.000000 -0.399654
3 -0.242247  0.000000  0.871069
4  0.975986 -0.763189  1.567743
5 -1.128100 -0.355459 -0.050403
6 -0.614838  0.359948  0.173833

对reindexing有效的那些插值方法也可用于fillna:
ffill向前填充,向下填充
bfill向后填充,向上填充

df=pd.DataFrame(np.random.randn(6,3))
df
          0         1         2
0  2.189955 -1.769679 -0.844384
1 -2.173418  0.289250 -2.216570
2 -0.414842 -0.115741  0.780312
3  0.244778  1.031849  0.604387
4  1.240619 -1.017771 -0.074853
5 -0.105774 -0.821069  0.118463
df.iloc[:2,1]=na
df
          0         1         2
0  2.189955       NaN -0.844384
1 -2.173418       NaN -2.216570
2 -0.414842 -0.115741  0.780312
3  0.244778  1.031849  0.604387
4  1.240619 -1.017771 -0.074853
5 -0.105774 -0.821069  0.118463
df.iloc[:4,2]=na
df
          0         1         2
0  2.189955       NaN       NaN
1 -2.173418       NaN       NaN
2 -0.414842 -0.115741       NaN
3  0.244778  1.031849       NaN
4  1.240619 -1.017771 -0.074853
5 -0.105774 -0.821069  0.118463
df.fillna(method='bfill')
          0         1         2
0  2.189955 -0.115741 -0.074853
1 -2.173418 -0.115741 -0.074853
2 -0.414842 -0.115741 -0.074853
3  0.244778  1.031849 -0.074853
4  1.240619 -1.017771 -0.074853
5 -0.105774 -0.821069  0.118463

比如说,你可以传入Series的平均值或中位数:

s=pd.Series([1,na,4,na,5,8])
s.fillna(s.mean())
0    1.0
1    4.5
2    4.0
3    4.5
4    5.0
5    8.0
dtype: float64

fillna()的参数

利用Python进行数据分析(五):数据清洗和准备
利用Python进行数据分析(五):数据清洗和准备

二、数据转换

1、移除重复数据

data = pd.DataFrame({'k1':['one','two'] * 3 + ['two'],'k2':[1,1,2,3,3,4,4]})
data
    k1  k2
0  one   1
1  two   1
2  one   2
3  two   3
4  one   3
5  two   4
6  two   4

DataFrame的duplicated方法返回一个布尔型Series,表示各行是否是重复行:

data.duplicated()
0    False
1    False
2    False
3    False
4    False
5    False
6     True
dtype: bool

还有一个与此相关的drop_duplicates方法,它会返回一个DataFrame,重复的数组会标为False:

data.drop_duplicates()
    k1  k2
0  one   1
1  two   1
2  one   2
3  two   3
4  one   3
5  two   4

这两个方法默认会判断全部列,你也可以指定部分列进行重复项判断。假设我们还有一列值,且只希望根据k1列过滤重复项:

data['v1'] = range(7)
data
    k1  k2  v1
0  one   1   0
1  two   1   1
2  one   2   2
3  two   3   3
4  one   3   4
5  two   4   5
6  two   4   6
data.drop_duplicates(['k1'])
    k1  k2  v1
0  one   1   0
1  two   1   1

duplicated和drop_duplicates默认保留的是第一个出现的值组合。传入keep=’last’则保留最后一个:

data.drop_duplicates(['k1'],keep='last')
    k1  k2  v1
4  one   3   4
6  two   4   6

2、利用函数或映射进行数据转换
对于许多数据集,你可能希望根据数组、Series或DataFrame列中的值来实现转换工作。我们来看看下面这组有关肉类的数据:

data = pd.DataFrame({'food':['s1','s2','s3','s4','s5','s6'],'price':range(6)})
data
  food  price
0   s1      0
1   s2      1
2   s3      2
3   s4      3
4   s5      4
5   s6      5

假设你想要添加一列表示该肉类食物来源的动物类型。我们先编写一个不同肉类到动物的映射:
如果有的大写,有的小写,用Series的str.lower方法,将各个值转换为小写。

data['animal'] = data['food'].map(foodt)
data
  food  price  animal
0   s1      0     cow
1   s2      1     pig
2   s3      2  salmon
3   s4      3     cow
4   s5      4     pig
5   s6      5  salmon

map是series的函数
3、替换值
利用fillna方法填充缺失数据可以看做值替换的一种特殊情况。前面已经看到,map可用于修改对象的数据子集,而replace则提供了一种实现该功能的更简单、更灵活的方式。我们来看看下面这个Series:

data = pd.Series([1,-999,2,-999,3,-1000])
data
0       1
1    -999
2       2
3    -999
4       3
5   -1000

999这个值可能是一个表示缺失数据的标记值。要将其替换为pandas能够理解的NA值,我们可以利用replace来产生一个新的Series(除非传入inplace=True):

data.replace(-999,np.nan)
0       1.0
1       NaN
2       2.0
3       NaN
4       3.0
5   -1000.0
dtype: float64

如果你希望一次性替换多个值,可以传入一个由待替换值组成的列表以及一个替换值:

data.replace([-999,1,-1000],np.nan)
0    NaN
1    NaN
2    2.0
3    NaN
4    3.0
5    NaN
dtype: float64

要让每个值有不同的替换值,可以传递一个替换列表:

data.replace([-999,-1000],[np.nan,0])
0    1.0
1    NaN
2    2.0
3    NaN
4    3.0
5    0.0
dtype: float64

传入的参数也可以是字典:

data.replace({-999:np.nan,-1000:0})
0    1.0
1    NaN
2    2.0
3    NaN
4    3.0
5    0.0
dtype: float64

4、重命名轴索引
跟Series中的值一样,轴标签也可以通过函数或映射进行转换,从而得到一个新的不同标签的对象。轴还可以被就地修改,而无需新建一个数据结构。

Original: https://blog.csdn.net/catchmeifyoucOol/article/details/121479677
Author: catchcatpath
Title: 利用Python进行数据分析(五):数据清洗和准备

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/754582/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球