pandas 数据清洗
·
目录
1.3填充空值:fillna()、ffill()、bfill()
1.缺失值
1.1判断有几个空值:isnull()
import numpy as np
import pandas as pd
s = pd.Series(['one','two',np.nan,'four',np.nan])
print('s原始数据:')
print(s)
print('*'*20)
print('s有多少个空值:')
print(s.isnull().sum())
运行结果:
s原始数据:
0 one
1 two
2 NaN
3 four
4 NaN
dtype: object
********************
有多少个空值:
2
1.2删除空值:dropna()
import numpy as np
import pandas as pd
data = pd.DataFrame([[8, 8,8],[np.nan,np.nan,np.nan],[np.nan,4,5],[np.nan,7,8]])
print('data原始数据:')
print(data)
print('*'*20)
print('只要有空值,就删除:')
print(data.dropna())
print('*'*20)
print('删除所有为空的行:')
print(data.dropna(how='all'))
print('*'*20)
print('每行至少保留一个非空值:')
print(data.dropna(thresh=1))
运行结果:
data原始数据:
0 1 2
0 8.0 8.0 8.0
1 NaN NaN NaN
2 NaN 4.0 5.0
3 NaN 7.0 8.0
********************
只要有空值,就删除:
0 1 2
0 8.0 8.0 8.0
********************
删除所有为空的行:
0 1 2
0 8.0 8.0 8.0
2 NaN 4.0 5.0
3 NaN 7.0 8.0
********************
每行至少保留一个非空值:
0 1 2
0 8.0 8.0 8.0
2 NaN 4.0 5.0
3 NaN 7.0 8.0
1.3填充空值:fillna()、ffill()、bfill()
import numpy as np
import pandas as pd
data = pd.DataFrame([[8, 8,8],[np.nan,np.nan,np.nan],[np.nan,4,5],[np.nan,7,8]])
print('data原始数据:')
print(data)
print('*'*20)
print('空值填充为0')
print(data.fillna(0))
print('*'*20)
print('每列使用字典填充不同的值:')
print(data.fillna({0:'a1',1:'b2',2:'c3'}))
print('*'*20)
print('用上面的非空值向下填充:')
print(data.fillna(method='ffill'))
print('*'*20)
#或者
print('用上面的非空值向下填充:')
print(data.ffill())
print('*'*20)
print('用下面的非空值向上填充:')
print(data.fillna(method='bfill'))
print('*'*20)
#或者
print('用下面的非空值向上填充:')
print(data.bfill())
print('*'*20)
运行结果:
data原始数据:
0 1 2
0 8.0 8.0 8.0
1 NaN NaN NaN
2 NaN 4.0 5.0
3 NaN 7.0 8.0
********************
空值填充为0
0 1 2
0 8.0 8.0 8.0
1 0.0 0.0 0.0
2 0.0 4.0 5.0
3 0.0 7.0 8.0
********************
每列使用字典填充不同的值:
0 1 2
0 8.0 8.0 8.0
1 a1 b2 c3
2 a1 4.0 5.0
3 a1 7.0 8.0
********************
用上面的非空值向下填充:
0 1 2
0 8.0 8.0 8.0
1 8.0 8.0 8.0
2 8.0 4.0 5.0
3 8.0 7.0 8.0
********************
用上面的非空值向下填充:
0 1 2
0 8.0 8.0 8.0
1 8.0 8.0 8.0
2 8.0 4.0 5.0
3 8.0 7.0 8.0
********************
用下面的非空值向上填充:
0 1 2
0 8.0 8.0 8.0
1 NaN 4.0 5.0
2 NaN 4.0 5.0
3 NaN 7.0 8.0
********************
用下面的非空值向上填充:
0 1 2
0 8.0 8.0 8.0
1 NaN 4.0 5.0
2 NaN 4.0 5.0
3 NaN 7.0 8.0
********************
2.异常值
2.1查看整体数据情况describe()
import numpy as np
import pandas as pd
data = pd.DataFrame(np.random.randn(1000,4))
print(data.describe())
运行结果:
0 1 2 3
count 1000.000000 1000.000000 1000.000000 1000.000000
mean 0.041550 -0.007959 -0.003183 -0.008919
std 0.967200 1.007417 1.012696 1.013143
min -3.321344 -3.337710 -3.147223 -3.248532
25% -0.614567 -0.685553 -0.672688 -0.698175
50% 0.048575 -0.017986 -0.017839 -0.010763
75% 0.688268 0.720620 0.697841 0.688270
max 2.992753 3.172907 2.940251 2.938432
2.2替换replace()
import numpy as np
import pandas as pd
data = pd.Series([1.,-999,2,-999,-1000,3.])
print('data原始数据:')
print(data)
print('*'*40)
print('单值替换:')
data = data.replace(-1000,88)
print(data)
print('*'*40)
print('列表多值替换:')
data = data.replace([-999,2],[np.nan,77])
print(data)
print('*'*40)
#或者
print('字典多值替换:')
data = data.replace({3:'san',1:'aaa'})
print(data)
运行结果:
data原始数据:
0 1.0
1 -999.0
2 2.0
3 -999.0
4 -1000.0
5 3.0
dtype: float64
****************************************
单值替换:
0 1.0
1 -999.0
2 2.0
3 -999.0
4 88.0
5 3.0
dtype: float64
****************************************
列表多值替换:
0 1.0
1 NaN
2 77.0
3 NaN
4 88.0
5 3.0
dtype: float64
****************************************
字典多值替换:
0 aaa
1 NaN
2 77.0
3 NaN
4 88.0
5 san
dtype: object
3.删除重复值
import pandas as pd
data = pd.DataFrame({'k1': list('abababaa'), 'k2': [1, 1, 2, 2, 3, 3, 4, 4]})
print('data原始数据:')
print(data)
print('*' * 20)
print('删除重复的行:')
print(data.drop_duplicates())
print('*' * 20)
print('删除k1列有重复值的行:')
print(data.drop_duplicates(['k1']))
运行结果:
data原始数据:
k1 k2
0 a 1
1 b 1
2 a 2
3 b 2
4 a 3
5 b 3
6 a 4
7 a 4
********************
删除重复的行:
k1 k2
0 a 1
1 b 1
2 a 2
3 b 2
4 a 3
5 b 3
6 a 4
********************
删除k1列有重复值的行:
k1 k2
0 a 1
1 b 1
4.数据转换映射
import pandas as pd
data = pd.DataFrame({'food': ['Banana', 'bone', 'Grass', 'fish', 'worm'],
'calorie': [10, 20, 30, 40, 50]})
eat_animal = {
'grass': 'cattle', # 牛, 牛吃草
'banana': 'monkey',
'fish': 'cat',
'worm': 'frog', # 青蛙,青蛙吃虫子
'bone': 'dog'}
print('data原始数据:')
print(data)
print('*' * 20)
print('food列转成小写并映射字典对象:')
data['animal'] = data['food'].str.lower().map(eat_animal)
print(data)
运行结果:
data原始数据:
food calorie
0 Banana 10
1 bone 20
2 Grass 30
3 fish 40
4 worm 50
********************
food列转成小写并映射字典对象:
food calorie animal
0 Banana 10 monkey
1 bone 20 dog
2 Grass 30 cattle
3 fish 40 cat
4 worm 50 frog
5.离散化
"""
pandas.cut(x, bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False, duplicates='raise', ordered=True)
参数说明:
x: 需要划分的连续型数据,可以是一个数组或Series。
bins: 划分的间隔,可以是一个整数、序列或间隔的字符串。如果是整数,则表示将x均匀划分为多少个区间。如果是序列,则表示划分的具体区间范围。如果是字符串,则表示划分的方式,比如'5'表示将x划分为5个等间隔的区间。
right: 是否包含右边界,默认为True,表示右边界为闭区间。
labels: 可选参数,用于标记每个划分的名称。
retbins: 是否返回划分的区间,默认为False,表示不返回。
precision: 浮点数的精度,默认为3。
include_lowest: 是否包含最低值,默认为False,表示最低值为开区间。
duplicates: 当传入的数据包含重复值时,如何处理。'raise'表示抛出ValueError异常,'drop'表示丢弃重复值。
返回值:
返回一个Categorical对象,表示划分后的离散分段。
"""
5.1分段cut()
cut()函数可以帮助我们将一组连续的数值数据分成若干个离散的区间,主要用于对数据从最大值到最小值进行等距划分
import numpy as np
import pandas as pd
#指定区间分段
print('要分段的数据:')
ages = [20, 21, 23,25,28,30,37,62,69,55,35,45,90]
print(ages)
print('*'*60)
print('区间:')
bins_ = [18, 25, 45, 70,100]
print(bins_)
print('*'*60)
print('标签:')
group_names = ['少年','青年','中年','老年']
print(group_names)
print('*'*60)
print('分段并打上标签:')
cut_ages = pd.cut(ages,bins=bins_,labels=group_names)
print(cut_ages)
print('*'*60)
print('每一段的数量:')
print(cut_ages.value_counts())
print('*'*60)
#均匀分段
print('data数据:')
data = np.random.randint(1,30,20)
print(data)
print('*'*60)
print('均匀分成5段:')
cut_data = pd.cut(data, 5)
print(cut_data)
print('*'*60)
print('data每段的数量:')
print(cut_data.value_counts())
运行结果:
要分段的数据:
[20, 21, 23, 25, 28, 30, 37, 62, 69, 55, 35, 45, 90]
************************************************************
区间:
[18, 25, 45, 70, 100]
************************************************************
标签:
['少年', '青年', '中年', '老年']
************************************************************
分段并打上标签:
['少年', '少年', '少年', '少年', '青年', ..., '中年', '中年', '青年', '青年', '老年']
Length: 13
Categories (4, object): ['少年' < '青年' < '中年' < '老年']
************************************************************
每一段的数量:
少年 4
青年 5
中年 3
老年 1
Name: count, dtype: int64
************************************************************
data数据:
[25 1 7 23 9 16 22 1 29 1 14 3 4 19 22 26 10 26 12 28]
************************************************************
均匀分成5段:
[(23.4, 29.0], (0.972, 6.6], (6.6, 12.2], (17.8, 23.4], (6.6, 12.2], ..., (23.4, 29.0], (6.6, 12.2], (23.4, 29.0], (6.6, 12.2], (23.4, 29.0]]
Length: 20
Categories (5, interval[float64, right]): [(0.972, 6.6] < (6.6, 12.2] < (12.2, 17.8] < (17.8, 23.4] <
(23.4, 29.0]]
************************************************************
data每段的数量:
(0.972, 6.6] 5
(6.6, 12.2] 4
(12.2, 17.8] 2
(17.8, 23.4] 4
(23.4, 29.0] 5
Name: count, dtype: int64
5.2分段qcut()
qcut()函数也能将一组连续的数据分成若干个离散的区间,与cut()函数不同的是,它能自动根据数据的分布情况,将数据划分成n个等频的区间。比如要把数据分为四份,则四段分别是数据的0-25%,25%-50%,50%-75%,75%-100%,每个间隔段里的元素个数尽可能都是相同的。
import numpy as np
import pandas as pd
print('要分段的数据factors:')
factors = np.random.randn(9)
print(factors)
print('*'*60)
print('factors用qcut()分成3段:')
cut_factors = pd.qcut(factors, 3)
print(cut_factors)
print('*'*60)
print('factors用qcut()分段每段的数量:')
print(cut_factors.value_counts())
print('*'*60)
print('factors用cut()分成3段:')
cut_factors = pd.cut(factors, 3)
print(cut_factors)
print('*'*60)
print('factors用cut()分段每段的数量:')
print(cut_factors.value_counts())
print('*'*60)
运行结果:
要分段的数据factors:
[-0.39570824 -1.46622264 -0.44875818 -0.23821268 0.99158197 -0.16520793
0.24477246 -3.47155469 -1.28229599]
************************************************************
factors用qcut()分成3段:
[(-0.727, -0.214], (-3.473, -0.727], (-0.727, -0.214], (-0.727, -0.214], (-0.214, 0.992], (-0.214, 0.992], (-0.214, 0.992], (-3.473, -0.727], (-3.473, -0.727]]
Categories (3, interval[float64, right]): [(-3.473, -0.727] < (-0.727, -0.214] < (-0.214, 0.992]]
************************************************************
factors用qcut()分段每段的数量:
(-3.473, -0.727] 3
(-0.727, -0.214] 3
(-0.214, 0.992] 3
Name: count, dtype: int64
************************************************************
factors用cut()分成3段:
[(-0.496, 0.992], (-1.984, -0.496], (-0.496, 0.992], (-0.496, 0.992], (-0.496, 0.992], (-0.496, 0.992], (-0.496, 0.992], (-3.476, -1.984], (-1.984, -0.496]]
Categories (3, interval[float64, right]): [(-3.476, -1.984] < (-1.984, -0.496] < (-0.496, 0.992]]
************************************************************
factors用cut()分段每段的数量:
(-3.476, -1.984] 1
(-1.984, -0.496] 2
(-0.496, 0.992] 6
Name: count, dtype: int64
************************************************************
6.实战案例
"""
url:https://lishi.tianqi.com/beijing/202309.html
抓取北京多个月份的天气数据并且清洗
"""
import time
import requests
from lxml import etree
import pandas as pd
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
}
def get_html(month,headers):
"""
:param month: 爬取的月份格式为 202009
:param headers: requests.get中的headers
:return: 返回一个html
"""
url = f'https://lishi.tianqi.com/beijing/{month}.html'
resp = requests.get(url,headers=headers)
html = etree.HTML(resp.text)
return html
# 月份列表
month_list = pd.period_range('202001','202201',freq='M').strftime('%Y%m')
# print(month_list)
# 爬取数据存入的列表
data_list = []
for month in month_list:
print(f'正在爬取{month}月数据')
html = get_html(month,headers)
datas = html.xpath('//div[@class="tian_three"]/ul/li')
for data in datas:
日期 = data.xpath('./div/text()')[0]
最高气温 = data.xpath('./div/text()')[1]
最低气温 = data.xpath('./div/text()')[2]
天气 = data.xpath('./div/text()')[3]
风向 = data.xpath('./div/text()')[4]
#每行数据以字典方式保存
item = {'日期':日期,
'最高气温': 最高气温,
'最低气温': 最低气温,
'天气': 天气,
'风向': 风向,
}
#把以字典保存的每行数据存入数据总列表
data_list.append(item)
time.sleep(1)
# print(日期,最高气温,最低气温,天气,风向)
print('爬取完成!')
# 把爬取的数据转换成df
df = pd.DataFrame(data_list)
# 爬取的数据保存为excel
df.to_excel(r'D:\北京天气历史数据.xlsx',index=False)
print('保存成功!')
# 读取保存的数据
df = pd.read_excel(r'D:\北京天气历史数据.xlsx')
print(df)
print('*'*100)
#数据清洗
#分割日期列
df[['日期new','星期','备注']] = df['日期'].str.split(' ',expand=True)
#把新的日期列转换为时间类型
df['日期new'] = pd.to_datetime(df['日期new'])
#把风向列分割
df[['风向2','风级']] = df['风向'].str.split(' ',expand=True)
# 把最高气温和最低气温转成浮点数
# df['最低气温'].replace('℃','')直接这样替换会不成功,
# 因为这种方式是对整个单元格操作,要单元个的内容匹配上了才替换
df['最低气温']=df['最低气温'].str.replace('℃','').astype('float')
df['最高气温']=df['最高气温'].str.replace('℃','').astype('float')
print(df)
print('*'*100)
df.info()
运行结果:
正在爬取202001月数据
正在爬取202002月数据
正在爬取202003月数据
正在爬取202004月数据
正在爬取202005月数据
正在爬取202006月数据
正在爬取202007月数据
正在爬取202008月数据
正在爬取202009月数据
正在爬取202010月数据
正在爬取202011月数据
正在爬取202012月数据
正在爬取202101月数据
正在爬取202102月数据
正在爬取202103月数据
正在爬取202104月数据
正在爬取202105月数据
正在爬取202106月数据
正在爬取202107月数据
正在爬取202108月数据
正在爬取202109月数据
正在爬取202110月数据
正在爬取202111月数据
正在爬取202112月数据
正在爬取202201月数据
爬取完成!
保存成功!
日期 最高气温 最低气温 天气 风向
0 2020-01-01 星期三 1℃ -10℃ 晴转多云 东北风 1级
1 2020-01-02 星期四 3℃ -9℃ 多云 西北风 1级
2 2020-01-03 星期五 6℃ -8℃ 晴 北风 1级
3 2020-01-04 星期六 8℃ -5℃ 晴转多云 北风 2级
4 2020-01-05 星期日 3℃ -5℃ 雪 东北风 1级
.. ... ... ... ... ...
757 2022-01-27 星期四 3℃ -5℃ 多云 西北风 3级
758 2022-01-28 星期五 4℃ -2℃ 阴 南风 1级
759 2022-01-29 星期六 -1℃ -9℃ 晴 北风 1级
760 2022-01-30 星期日 3℃ -3℃ 霾 西北风 2级
761 2022-01-31 星期一 3℃ -5℃ 晴 西北风 4级
[762 rows x 5 columns]
*****************************************************************************************
日期 最高气温 最低气温 天气 风向 日期new 星期 备注 风向2 风级
0 2020-01-01 星期三 1.0 -10.0 晴转多云 东北风 1级 2020-01-01 星期三 东北风 1级
1 2020-01-02 星期四 3.0 -9.0 多云 西北风 1级 2020-01-02 星期四 西北风 1级
2 2020-01-03 星期五 6.0 -8.0 晴 北风 1级 2020-01-03 星期五 北风 1级
3 2020-01-04 星期六 8.0 -5.0 晴转多云 北风 2级 2020-01-04 星期六 北风 2级
4 2020-01-05 星期日 3.0 -5.0 雪 东北风 1级 2020-01-05 星期日 东北风 1级
.. ... ... ... ... ... ... ... .. ... ..
757 2022-01-27 星期四 3.0 -5.0 多云 西北风 3级 2022-01-27 星期四 西北风 3级
758 2022-01-28 星期五 4.0 -2.0 阴 南风 1级 2022-01-28 星期五 南风 1级
759 2022-01-29 星期六 -1.0 -9.0 晴 北风 1级 2022-01-29 星期六 北风 1级
760 2022-01-30 星期日 3.0 -3.0 霾 西北风 2级 2022-01-30 星期日 西北风 2级
761 2022-01-31 星期一 3.0 -5.0 晴 西北风 4级 2022-01-31 星期一 西北风 4级
[762 rows x 10 columns]
*****************************************************************************************
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 762 entries, 0 to 761
Data columns (total 10 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 日期 762 non-null object
1 最高气温 762 non-null float64
2 最低气温 762 non-null float64
3 天气 762 non-null object
4 风向 762 non-null object
5 日期new 762 non-null datetime64[ns]
6 星期 762 non-null object
7 备注 762 non-null object
8 风向2 762 non-null object
9 风级 762 non-null object
dtypes: datetime64[ns](1), float64(2), object(7)
memory usage: 59.7+ KB
保存的excel:

后续持续学习更新
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)