002 pandas初步数据清洗

文章目录

  • 数据清洗
      • 初始化 isnull() notnull()
      • 滤除缺失数据 dropna()
        • Series
        • DataFram
        • thresh = 2
      • 填充缺失数据 fillna()
        • 用字符填充
        • 用字典填充
        • 原地修改 inplace=True
        • 指定位置填充
        • 根据前面数据填充 method='ffill'
        • 限制填充数量
        • 发挥想象填充
      • 去重 drop_duplicates ()
      • 数据映射
      • 替换 replace()
      • 重命名索引轴 rename()
      • 面元划分 cut()
        • 手动设置区间 进行划分
          • 默认是左开右闭区间
          • 分组情况
          • 每个元素对应的组号
          • 统计各个面元内的数量
          • 修改区间闭合情况 用label参数 设置组名
        • 分成等长区间
        • 分成样本数尽可能相等的区间 qcut()
      • 检测和过滤异常值
          • describe()方法
          • series 选出绝对值超过3 的值
          • DataFrame选出包含 绝对值大于2 的行
      • 排列和随机采样
          • np.random.permutation() && DataFrame.take()
          • DataFrame.sample()
      • 计算指标/哑变量
        • 简单
          • 指标DataFrame的列加上一个前缀,以便能够跟其他数据进行合并
          • join() 合并 (注意是双列表)
        • 高级---范例:作者当指标
        • 一个秘诀
      • 字符串操作
        • 内置
        • 正则
        • pandas扩展字符串操作

数据清洗

初始化 isnull() notnull()

string_data = pd.Series(['aardvark', 'artichoke', np.nan, 'avocado'])

string_data[0] = None
print(string_data)
print(string_data.isnull())
print(string_data.notnull())

滤除缺失数据 dropna()

Series

data = pd.Series([1, np.nan, 3.5, np.nan, 7])
print(data)
print(data.dropna())

DataFram

二维的结构,dropna()默认丢弃所有包含nan的行,axis=1 是在列上操作

how = ‘all’ 表示,全行都为空才删除

axis = 1 表示 按列 执行

data = pd.DataFrame([[1., 6.5, 3.], [1., NA, NA], [NA, NA, NA], [NA, 6.5, 3.]])
print(data.dropna())
print(data.dropna(how='all'))
print(data.dropna(axis=1, how='all'))

thresh = 2

thresh = 2 表示 全行有2个nan时,删除该行

df = pd.DataFrame(np.random.randn(7, 3))
df.iloc[:4, 1] = NA
df.iloc[:2, 2] = NA
print(df.dropna())
# thresh 粒度
print(df.dropna(thresh=2))

填充缺失数据 fillna()

002 pandas初步数据清洗_第1张图片

用字符填充

df.fillna(0)

用字典填充

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

df.fillna({1: 0, 2: 2})

原地修改 inplace=True

df.fillna(9, inplace=True)

指定位置填充

ddf = pd.DataFrame(np.random.randn(6, 3))
ddf.iloc[2:, 1] = np.nan
ddf.iloc[4:, 2] = NA
ddf.iloc[4, 1] = 99
print(ddf)

根据前面数据填充 method=‘ffill’

ddf.fillna(method='ffill')

限制填充数量

根据前面的数据填充,但是只填充 limit 个 , axis用于控制 方向

ddf.fillna(method='ffill', limit=1, axis=1)

发挥想象填充

比如用平均值填充

data = pd.Series([1., NA, 3.5, NA, 7])
data.fillna(data.mean())

去重 drop_duplicates ()

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

drop_duplicates() 则能去重, 默认判断全部列

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

根据部分列去重

keep参数选择 留下哪一个。

data['v1'] = range(7)
print(data)
print(data.drop_duplicates(['k1']))
print(data.drop_duplicates(['k1', 'k2']))
print(data.drop_duplicates(['k1', 'k2'], keep='last'))

数据映射

data = pd.DataFrame({'food': ['bacon', 'pulled pork', 'bacon', 'Pastrami', 'corned beef','Bacon', 'pastrami', 'honey ham', 'nova lox'], 'ounces': [4, 3, 12, 6, 7.5, 8, 3, 5, 6]})

meat_to_animal = {
    'bacon': 'pig',
    'pulled pork': 'pig',
    'pastrami': 'cow',
    'corned beef': 'cow',
    'honey ham': 'pig',
    'nova lox': 'salmon'
}

data.animal = data.food.map(lambda x : meat_to_animal[x.lower()])
data

替换 replace()

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

替换某个值

data.replace(-999, np.nan)

传入列表 替换值

data.replace([-999, -1000], NA)

传入字典替换值

data.replace({-999: 666, -1000: 123})

重命名索引轴 rename()

data = pd.DataFrame(np.arange(12).reshape((3, 4)), index=['ohio', 'Colorado', 'New York'], columns=['one', 'two', 'three', 'four'])

# 设置索引 开头大写 和其他
data.rename(index=str.title,columns=str.upper,inplace=True)

# 修改索引的名字
data.rename(index={'Ohio': 'Aaa'}, columns={'THREE': 'ttt'})

面元划分 cut()

手动设置区间 进行划分

默认是左开右闭区间
ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 30, 45, 41, 32]
bins = [0, 20, 30, 40, 100]
cats = pd.cut(ages, bins)
分组情况
cats.categories
每个元素对应的组号
cats.codes
统计各个面元内的数量
pd.value_counts(cats)
修改区间闭合情况 用label参数 设置组名
group_names = ['Youth', 'YoungAdult', 'MiddleAged', 'Senior']
cats2 = pd.cut(ages, bins, right=False, labels=group_names)

分成等长区间

传递数量而不是边界,会分成等长区间,precision参数确定小数精确度

data = np.random.randn(20)
print(pd.cut(data, 4, precision=3))

分成样本数尽可能相等的区间 qcut()

据数据的分布情况,cut可能无法使各个面元中含有相同数量的数据点

qcut根据样本分位数切割成大小基本相等的面元

data = np.random.randn(1000)
catsq = pd.qcut(data, 4)
pd.value_counts(catsq)

检测和过滤异常值

describe()方法
data = pd.DataFrame(np.random.randn(1000, 4))
data.describe()
series 选出绝对值超过3 的值
ss = data[2]
ss[np.abs(ss)>3]
DataFrame选出包含 绝对值大于2 的行
data[(np.abs(data) > 2).any(1)]

排列和随机采样

np.random.permutation() && DataFrame.take()
df = pd.DataFrame(np.arange(20).reshape((5, 4)))

np.random.permutation() 连续数组随机重排

sampler = np.random.permutation(5)

take()方法 根据 permutation() 生成的序列 重排行号

df.take(sampler)
DataFrame.sample()

上面的重排可以用sample()替代

注意和行或者列上 索引的字符数量一致

df.sample(5)
df.sample(4,axis=1)

计算指标/哑变量

简单

df = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'b'], 'data1': range(6)})
print(df)
print(pd.get_dummies(df['key']))
指标DataFrame的列加上一个前缀,以便能够跟其他数据进行合并
dummies= pd.get_dummies(df['key'], prefix='key')
join() 合并 (注意是双列表)
df[['data1']].join(dummies)

高级—范例:作者当指标

获取作者并且去重

import pandas as pd
mnames = ['movie_id', 'title', 'genres']
movies = pd.read_csv('datasets/movielens/movies.dat',engine='python',sep='::', header=None, names=mnames)

all_genres = []
for x in movies.genres:
    all_genres.extend(x.split('|'))
genres = pd.unique(all_genres)

第一步:构建指标DataFrame的方法之一是从一个全零DataFrame开始

zero_matrix = np.zeros((len(movies),len(genres)))

第二部:现在,迭代每一部电影,并将dummies各行的条目设为1,我们使用dummies.columns来计算每个类型的列索引 dummies.columns.get_indexer()

for i,gen in enumerate(movies.genres):
    incides = dummies.columns.get_indexer(gen.split('|'))
    dummies.iloc[i,incides] = 1

第三步:合并 , 用add_prefix() 加一个前缀

movies.join(dummies.add_prefix('Genre_'))

一个秘诀

个对统计应用有用的秘诀是:结合get_dummies和诸如cut之类的离散化函数

values = np.random.rand(10)
bins = [0, 0.2, 0.4, 0.6, 0.8, 1]
print(pd.cut(values, bins))
print(pd.get_dummies(pd.cut(values, bins)))

字符串操作

内置

002 pandas初步数据清洗_第2张图片002 pandas初步数据清洗_第3张图片

val = 'a,b,  guido'
# 切割字符串
print(val.split(','))
pieces = [x.strip() for x in val.split(',')]
# 连接字符串
print('::'.join(pieces))
# 检测子串
print('b' in pieces)
print(val.find(','))
print(val.index(','))
print(val.count(','))

正则

基础用法

# split()
text = "foo    bar\t baz  \tqux"
print(re.split('\s+', text))

# compile()
regex = re.compile('\s+')
print(regex.split(text))

# findall()
print(regex.findall(text))

进阶一下

# 返回所有的匹配内容
pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}'
regex = re.compile(pattern, flags=re.IGNORECASE)
print(regex.findall(email_text))

# 仅仅返回一个
print(regex.search(email_text))

# regex.match则将返回None,因为它只匹配出现在字符串开头的模式
print(regex.match(email_text))

# sub() 把匹配到的替换成指定的,返回一个新的字符串
print(regex.sub('xxxxxx', email_text))

# 将各个地址分成3个部分,用括号括住就行。
pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})'
regex = re.compile(pattern, flags=re.IGNORECASE)
print(regex.match('[email protected]').groups())
print(regex.match('[email protected]').group())
print(regex.findall(email_text))

pandas扩展字符串操作

data = {'Dave': '[email protected]', 'Steve': '[email protected]',
        'Rob': '[email protected]', 'Wes': np.nan}
data = pd.Series(data)
print(data)
print(data.isnull())

# str.contains检查各个电子邮件地址是否含有"gmail"
print(data.str.contains('gmail'))

# 可以使用正则表达式
parttern = '([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\\.([A-Z]{2,4})'
print(data.str.findall(parttern, flags=re.IGNORECASE))
print(data.str.match(pattern, flags=re.IGNORECASE))
print(data.str[:5])

002 pandas初步数据清洗_第4张图片
002 pandas初步数据清洗_第5张图片

你可能感兴趣的:(python)