使用日期和时间来分析数据集通常很麻烦。你可以根据自己的情况考虑不同长度的月份, 工作日和周末的不同分布, leap年和可怕的时区。因此, Python具有专门为日期和时间设计的数据类型, 称为datetime。
但是, 在许多数据集中, 你会发现日期以字符串表示。因此, 在本教程中, 你将学习如何将日期字符串转换为datetime格式, 并了解如何使用其功能强大的工具有效处理复杂的时间序列数据。
处理日期的不同表示
主要挑战通常是指定如何表达日期字符串。例如, ” 2018年6月6日星期三”也可以表示为” 6/6/18″和” 06-06-2018″。这些都通知你相同的日期, 但是你可能可以想象, 转换每个日期的代码略有不同。花点时间检查下面的函数调用:
from datetime import datetime
# Define dates as strings
date_str1 = 'Wednesday, June 6, 2018'
date_str2 = '6/6/18'
date_str3 = '06-06-2018'
# Define dates as datetime objects
date_dt1 = datetime.strptime(date_str1, '%A, %B %d, %Y')
date_dt2 = datetime.strptime(date_str2, '%m/%d/%y')
date_dt3 = datetime.strptime(date_str3, '%m-%d-%Y')
# Print converted dates
print(date_dt1)
print(date_dt2)
print(date_dt3)
2018-06-06 00:00:00
2018-06-06 00:00:00
2018-06-06 00:00:00
首先, 从datetime模块导入datetime类型。然后, 日期字符串将传递给.strptime()方法, 然后传递给Python的strptime指令。你可以结合使用伪指令, 特殊字符(例如, 在上述情况下为、、 /或-)和空格, 以匹配你要解析的日期字符串。如你所见, 由于所有三个日期字符串都表示相同的日期, 因此生成的datetime对象是相同的。
你可以在Python文档中找到指令的完整列表, 但下表是与你在上方看到的最相关的表:
代码 | 含义 | 例子 |
---|---|---|
%A | 工作日为语言环境的全名。 | 星期三 |
%a | 工作日为语言环境的缩写名称。 | 星期三 |
%B | 月份作为语言环境的全名。 | 六月 |
%d | 一个月中的某天。 | 06 |
%m | 以数字表示的月份。 | 6 |
%Y | 四位数的年份。 | 2018 |
%y | 两位数的年份。 | 18 |
转换日期字符串列
现在你已经熟悉了Python的strptime指令, 让我们学习如何将数据集中的整个日期字符串列转换为datetime格式。
从现在开始, 你将使用一个名为eth的数据框架, 其中包含有关以太坊的一些历史数据, 这是一种加密货币, 其区块链由以太坊平台生成。你的数据集包含以下列:
- 日期:日期, 每天世界标准时间00:00。
- txVolume:未经调整的度量值, 以美元为单位, 表示区块链上的输出。
- txCount:在公共区块链上发生的交易数量。
- marketCap:以美元为单位的价格乘以流通的单位数。
- 价格:UTC 00:00的美元开盘价。
- generateCoins:已被开采的新硬币数量。
- exchangeVolume:GDAX和Bitfinex等交易所的交易量, 以美元为单位。
这是数据集的前几行。请注意日期的表示方式, 以便以后可以使用正确的指令:
print(eth.head())
date txVolume(USD) txCount marketcap(USD) price(USD) \
0 2015-08-10 1.193012e+06 2037 43130000.0 0.713989
1 2015-08-11 1.052027e+06 4963 42796500.0 0.708087
2 2015-08-12 7.923370e+05 2036 64018400.0 1.060000
3 2015-08-13 2.181182e+06 2842 73935400.0 1.220000
4 2015-08-14 4.154763e+06 3174 109594000.0 1.810000
generatedCoins exchangeVolume(USD)
0 27817.34375 405283.0
1 28027.81250 1463100.0
2 27370.93750 2150620.0
3 28268.12500 4068680.0
4 31106.71875 4637030.0
让我们确认日期列是否需要转换:
# Confirm the date column is a string
print(eth.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1014 entries, 0 to 1013
Data columns (total 7 columns):
date 1014 non-null object
txVolume(USD) 1014 non-null float64
txCount 1014 non-null int64
marketcap(USD) 1014 non-null float64
price(USD) 1014 non-null float64
generatedCoins 1014 non-null float64
exchangeVolume(USD) 1014 non-null float64
dtypes: float64(5), int64(1), object(1)
memory usage: 55.5+ KB
None
date列确实是一个字符串, 记住-在Python中被表示为对象类型。你可以使用pandas中的.to_datetime()方法将其转换为datetime类型。下面的控制台包含转换列的调用。你能否通过根据数据集中的日期表示方式指定指令来完成它?
你是否使用’%Y-%m-%d’完成了?大!
日期时间对象的组成部分
现在你将datetime对象作为日期列, 你可以提取日期的特定组成部分, 例如月, 日或年, 所有这些都可以用作对象的属性:
# Print datetime attributes
print(eth['date'][0].month)
print(eth['date'][0].day)
print(eth['date'][0].year)
8
10
2015
日期属性通常用于按特定时间范围对数据进行分组。例如, 你可以查看每年生成多少醚:
from collections import defaultdict
import matplotlib.pyplot as plt
# Initialize defaultdict of type float
yearly_total_coins = defaultdict(float)
# Loop over the rows of eth
for day in eth.iterrows():
# Get the date
dates = day[1][0]
# Get the number of coins generated
num_coins = day[1][5]
# Add the total number of coins to the current value for the year
yearly_total_coins[dates.year] += num_coins
# Print yearly_total_coins
print(yearly_total_coins)
# Visualize aggregated data
plt.bar(range(len(yearly_total_coins)), list(yearly_total_coins.values()), align='center')
plt.xticks(range(len(yearly_total_coins)), list(yearly_total_coins.keys()))
plt.title('# of ethers generated by year')
plt.show()
defaultdict(<class 'float'>, {2015: 3805167.8125, 2016: 11321892.96875, 2017: 9230132.65625, 2018: 2849975.625})
加减时间
使用日期时, 另一种常见情况是从某个日期获得过去30、60或90天的日期。在Python中, datetime模块中的timedelta对象用于表示datetime对象中的差异。你可以通过传递任意数量的关键字参数(例如天, 秒, 微秒, 毫秒, 分钟, 小时和周)来创建时间增量。
一旦有了一个timedelta对象, 就可以从datetime对象中添加或减去它, 以获得另一个datetime对象。在下面的控制台中尝试:
用DatetimeIndex索引熊猫数据框
将date列转换为datetime格式后, 通常最好按日期对DataFrame进行索引, 从而创建DatetimeIndex。与datetime类型类似, DatetimeIndex是一种特殊的索引类型, 旨在与日期和时间一起使用。通过使用inset参数设置为True的.set_index()方法, 可以从数据集中删除日期列, 并将其附加为DataFrame的索引:
# Set index
eth.set_index('date', inplace=True)
print(eth.head(5))
txVolume txCount marketCap price generatedCoins \
date
2015-08-10 1.193012e+06 2037 43130000.0 0.713989 27817.34375
2015-08-11 1.052027e+06 4963 42796500.0 0.708087 28027.81250
2015-08-12 7.923370e+05 2036 64018400.0 1.060000 27370.93750
2015-08-13 2.181182e+06 2842 73935400.0 1.220000 28268.12500
2015-08-14 4.154763e+06 3174 109594000.0 1.810000 31106.71875
exchangeVolume
date
2015-08-10 405283.0
2015-08-11 1463100.0
2015-08-12 2150620.0
2015-08-13 4068680.0
2015-08-14 4637030.0
在DataFrame中设置DatetimeIndex可以解锁一整套有用的功能。例如, 当可视化时间序列数据时, 熊猫会自动为x轴创建合理间隔的日期标签:
eth.txCount.plot(title='# of transactions')
plt.show()
很整洁吧?
部分字符串索引和切片
也许最有用的功能是部分字符串索引和切片, 这使你可以轻松地子集数据。假设你想仔细观察上图所示的2018年1月左右的峰值。以下代码使用部分字符串索引和切片来观察2017年12月至2018年2月之间的交易数量。
# Subset data around peak
peak_eth = eth['2017-12': '2018-2']
peak_eth.txCount.plot(title='# of transactions around peak')
好吧, 那很容易!你是否注意到部分字符串索引包含边界, 这与典型的Python索引不同?
概括
从股票价格到航班时刻, 包含日期和时间的数据在各种各样的领域中都是不成熟的。能够有效处理此类数据对于回答从何时, 多长时间或多频率开始的问题至关重要。
在本教程中, 你:
- 了解有关Python的指令以处理日期的各种表示方式。
- 了解了如何使用datetime模块中的.strptime()方法将字符串转换为日期。
- 了解了如何使用pandas中的.to_datetime()方法转换DataFrames中的日期字符串列。
- 了解了datetime对象的组件以及如何将其作为对象的属性进行访问。
- 了解了如何使用timedelta对象进行日期算术。
- 学习了使用DatetimeIndex为DataFrames编制索引, 并探讨了其有用性的一些示例。
Python中的datetime和DatetimeIndex对象提供了一种更易于管理和直观的方式来处理日期和时间。如果你对学习更高级的技术感到好奇, 并且渴望获得一些动手实践来操纵, 分析和可视化时间序列数据, 请查看Python中的操纵时间序列数据, Python中的时间序列分析简介和时间可视化有关srcmini的Python课程中的系列数据。
学习愉快!
评论前必须登录!
注册