时间序列数据处理
to_datetime
与 dt.strftime
实际工作中,经常会遇到大量的时间序列数据。这些时间序列的原始数据一般为文本格式,我们需要将它转化为时间日期格式。 Pandas 提供了 to_datetime
函数将其他日期时间格式转化为 Python 的日期时间格式。例如:
import pandas as pd
pd.to_datetime('20200514')
Timestamp('2020-05-14 00:00:00')
pd.to_datetime('2020/05/14')
Timestamp('2020-05-14 00:00:00')
pd.to_datetime('2020-05-14')
Timestamp('2020-05-14 00:00:00')
在上面的代码中可以看出,to_datetime
方法将不同类型的时间数据字符串转化为 Timestamp 格式:年-月-日 时:分:秒
。另外一个函数dt.strftime
可以将 Pandas 的 Timestamp 格式数据转化为其他格式的字符串,例如:
df = pd.DataFrame({'入校时间': ['2016-09-15', '2017-03-23', '2018-09-05'], '统计学': [85, 68, 90], '高数': [82, 63, 88], '英语': [84, 90, 78], '姓名': ['张三', '李四', '王五']})
df
|
入校时间 |
统计学 |
高数 |
英语 |
姓名 |
0 |
2016-09-15 |
85 |
82 |
84 |
张三 |
1 |
2017-03-23 |
68 |
63 |
90 |
李四 |
2 |
2018-09-05 |
90 |
88 |
78 |
王五 |
df.iloc[0, 0] # 原始数据中的时间为字符串
'2016-09-15'
df['入校时间'] = pd.to_datetime(df['入校时间']) # 将原始数据中的时间转化为 python 的日期格式
df
|
入校时间 |
统计学 |
高数 |
英语 |
姓名 |
0 |
2016-09-15 |
85 |
82 |
84 |
张三 |
1 |
2017-03-23 |
68 |
63 |
90 |
李四 |
2 |
2018-09-05 |
90 |
88 |
78 |
王五 |
df.iloc[0, 0]
Timestamp('2016-09-15 00:00:00')
df['入校时间'].dt.strftime('%m-%d-%y') # 将日期格式转化为自定义格式的字符串
0 09-15-16
1 03-23-17
2 09-05-18
Name: 入校时间, dtype: object
df['入校时间'].dt.strftime('%B-%d-%y') # 将日期格式转化为自定义格式的字符串,小写 Y 年份显示两位
0 September-15-16
1 March-23-17
2 September-05-18
Name: 入校时间, dtype: object
df['入校时间'].dt.strftime('%B-%d-%Y') # 将日期格式转化为自定义格式的字符串,大写 Y 则年份显示四位
0 September-15-2016
1 March-23-2017
2 September-05-2018
Name: 入校时间, dtype: object
df['入校时间'].dt.strftime('%Y-%W') # 将日期格式转化为自定义格式的字符串,大写 W 显示的为该年第几周
0 2016-37
1 2017-12
2 2018-36
Name: 入校时间, dtype: object
df['入校时间'].dt.strftime('%Y-%m-%w') # 将日期格式转化为自定义格式的字符串,小写 w 显示的为该月第几周
0 2016-09-4
1 2017-03-4
2 2018-09-3
Name: 入校时间, dtype: object
数据聚合函数resample
对于很多时间序列数据,有时候经常需要对它们按一定周期进行数据聚合,可以用 Pandas 提供的resample
函数。resample 方法中的小括号中用不同参数表示聚合的频率。举例:
import numpy as np
index = pd.date_range('12/24/2019', periods = 10, freq ='D') # 生成一个时间序列,频率为天,周期数为 10
index
DatetimeIndex(['2019-12-24', '2019-12-25', '2019-12-26', '2019-12-27',
'2019-12-28', '2019-12-29', '2019-12-30', '2019-12-31',
'2020-01-01', '2020-01-02'],
dtype='datetime64[ns]', freq='D')
df = pd.DataFrame(np.arange(10),index = index) # 创建一个包含时间序列的 DataFrame 数据表
df
|
0 |
2019-12-24 |
0 |
2019-12-25 |
1 |
2019-12-26 |
2 |
2019-12-27 |
3 |
2019-12-28 |
4 |
2019-12-29 |
5 |
2019-12-30 |
6 |
2019-12-31 |
7 |
2020-01-01 |
8 |
2020-01-02 |
9 |
df.resample('M').sum() # 用 resample 方法按月('M')对数据聚合
|
0 |
2019-12-31 |
28 |
2020-01-31 |
17 |
df.resample('3D').sum() # 用 resample 方法每 3 天('3D')对数据聚合
|
0 |
2019-12-24 |
3 |
2019-12-27 |
12 |
2019-12-30 |
21 |
2020-01-02 |
9 |
df.resample('w').sum() # 用 resample 方法每周('w')对数据聚合
|
0 |
2019-12-29 |
15 |
2020-01-05 |
30 |
resample
的其他参数中, ‘T’ 表示分钟,‘H’ 表示小时,除了跟sum()
方法外,还可以跟asfreq()
,ffill
,apply()
等。
数据清洗
数据替换replace
, fillna
在进行数据处理时,经常需要对原始数据的一些异常值或错误值进行批量处理。 Pandas 提供了replace
函数方便地进行这项操作。replace
函数第一项为原数据中的值,第二项为需要替换的值。例如,有下面的学生成绩:
import pandas as pd
import numpy as np
df = pd.DataFrame(np.array([[85, 68, 90], [82, 63, 88], [84, 90, 78]]), columns=['统计学', '高数', '英语'], index=['张三', '李四', '王五'])
df
|
统计学 |
高数 |
英语 |
张三 |
85 |
68 |
90 |
李四 |
82 |
63 |
88 |
王五 |
84 |
90 |
78 |
将其中的分数 90 替换为缺失值 NaN,注意,replace
返回了一个新的数据,但原始数据并没有改变。
df.replace(90, np.nan)
|
统计学 |
高数 |
英语 |
张三 |
85 |
68 |
85 |
李四 |
82 |
63 |
88 |
王五 |
84 |
85 |
78 |
df # 原始数据并没有变
|
统计学 |
高数 |
英语 |
张三 |
85 |
68 |
90 |
李四 |
82 |
63 |
88 |
王五 |
84 |
90 |
78 |
若需要原始数据改变,需要跟上参数inplace = True
,下面讲到的函数fillna
、drop_duplicates
、dropna
、 rename
等也可以跟这个参数将原始数据改变。
df.replace(90, np.nan, inplace = True)
df # 原始数据改变了
|
统计学 |
高数 |
英语 |
张三 |
85 |
68.0 |
NaN |
李四 |
82 |
63.0 |
88.0 |
王五 |
84 |
NaN |
78.0 |
Pandas 提供fillna
函数批量替换数据表中的缺失值 NaN。例如:
df.fillna(80) # 将缺失值替换为 80
|
统计学 |
高数 |
英语 |
张三 |
85 |
68.0 |
80.0 |
李四 |
82 |
63.0 |
88.0 |
王五 |
84 |
80.0 |
78.0 |
df.fillna('missing') # 将缺失值替换为一个字符串
|
统计学 |
高数 |
英语 |
张三 |
85 |
68.0 |
missing |
李四 |
82 |
63.0 |
88.0 |
王五 |
84 |
missing |
78.0 |
Pandas 还可以直接调用isnull
函数判断数据是否为缺失值:
df['英语'].isnull()
张三 True
李四 False
王五 False
Name: 英语, dtype: bool
重复值处理drop_duplicates
在数据量比较大时,经常会遇到重复数据的问题,可以使用函数drop_duplicates
将重复数据去掉。例如:
df = pd.DataFrame([['一班', '男', 85, 68, 90], ['一班', '男', 85, 68, 90], ['二班', '女',84, 90, 78], ['三班', '女',75, 68, 80],\
['二班', '女',69, 55, 63], ['一班', '男', 89, 95, 93]], columns=['班级','性别','统计学','高数','英语'],\
index=['张三', '张三', '王五', '马六', '陈小虎', '魏大帅'])
df
|
班级 |
性别 |
统计学 |
高数 |
英语 |
张三 |
一班 |
男 |
85 |
68 |
90 |
张三 |
一班 |
男 |
85 |
68 |
90 |
王五 |
二班 |
女 |
84 |
90 |
78 |
马六 |
三班 |
女 |
75 |
68 |
80 |
陈小虎 |
二班 |
女 |
69 |
55 |
63 |
魏大帅 |
一班 |
男 |
89 |
95 |
93 |
前两行的数据完全相同,使用函数drop_duplicates
处理:
df.drop_duplicates()
|
班级 |
性别 |
统计学 |
高数 |
英语 |
张三 |
一班 |
男 |
85 |
68 |
90 |
王五 |
二班 |
女 |
84 |
90 |
78 |
马六 |
三班 |
女 |
75 |
68 |
80 |
陈小虎 |
二班 |
女 |
69 |
55 |
63 |
魏大帅 |
一班 |
男 |
89 |
95 |
93 |
缺失值处理drop_na
dropna
函数可以将数据表中包含缺失值的行去除掉,与drop_duplicates
相比,该方法的可调节参数更多些。它的语法如下:
DataFrame.dropna(axis=0, how='any', thresh=None, inplace=False)} |
axis |
axis=0 表示删除含空值所在行,axis=1 表示删除含空值所在列 |
how |
默认为 how='any',表示若有空值,就删除 |
how='all',表示全部是空值才删除该行或该列 |
thresh |
空值的个数,作为行或列的删除标准 |
inplace |
若 inplace=True,表示处理后的数据替换原数据 |
df = pd.DataFrame({'统计学': [85, 68, np.nan], '高数': [82, 75, 88], '英语': [np.nan, 90, 78]}, index=['张三', '李四', '王五'])
df
|
统计学 |
高数 |
英语 |
张三 |
85.0 |
82 |
NaN |
李四 |
68.0 |
75 |
90.0 |
王五 |
NaN |
88 |
78.0 |
df.dropna() # 默认为删除含有空值的行,并且只要行里面有 Nan 值,就删除
|
统计学 |
高数 |
英语 |
李四 |
68.0 |
75 |
90.0 |
df.dropna(axis = 1) # 删除含有空值的列
df.dropna(how = 'all') # 全部是空值才删除
|
统计学 |
高数 |
英语 |
张三 |
85.0 |
82 |
NaN |
李四 |
68.0 |
75 |
90.0 |
王五 |
NaN |
88 |
78.0 |
重命名rename
在处理数据表时,有时候要给数据的行名或列名重命名,此时要用到rename
函数,rename
函数中的参数为一个字典形式:替换前的名字为字典的 key,替换后的名字为字典的 value。
df = pd.DataFrame({'统计学': [85, 68, 90], '高数': [82, 63, 88], '英语': [84, 90, 78]})
df
|
统计学 |
高数 |
英语 |
0 |
85 |
82 |
84 |
1 |
68 |
63 |
90 |
2 |
90 |
88 |
78 |
df.rename(columns = {'统计学': '科目A', '高数': '科目B'}) # 更改其中两列的列名
|
科目A |
科目B |
英语 |
0 |
85 |
82 |
84 |
1 |
68 |
63 |
90 |
2 |
90 |
88 |
78 |