Pandas时间序列数据框架方法

67 阅读9分钟

Pandas DataFrame/Series有几个与时间序列有关的方法。

入门

记住,在每个代码片段的顶部添加 所需的启动代码到每个代码片段的顶部。这个代码段将使本文中的代码能够无误地运行。

所需的启动代码

import pandas as pd
import numpy

在进行任何数据操作之前,需要安装两个新的库。

  • [pandas](https://blog.finxter.com/pandas-quickstart/)库实现了对DataFrame的访问/从DataFrame的访问。
  • 该库支持多维数组。 [numpy](https://blog.finxter.com/numpy-tutorial/)库支持多维数组和矩阵,此外还有一系列数学函数。

要安装这些库,请导航到IDE终端。在命令提示符下($),执行下面的代码。对于本例中使用的终端,命令提示符是一个美元符号($)。你的终端提示可能不同。

$ pip install pandas

点击键盘上的<Enter> 键,开始安装过程。

$ pip install numpy

按键盘上的<Enter> 键,开始安装过程。

如果安装成功,终端会显示一条信息,说明这一点。

DataFrame asfreq()

asfreq() 方法将一个时间序列转换为一个指定的频率。

该方法的语法如下。

DataFrame.asfreq(freq, method=None, how=None, normalize=False, fill_value=None)
参数说明
freq点击这里查看频率,或者导航到一个IDE并运行。print(pd.tseries.offsets.__all__)
method该参数完成索引系列(非NaN)中的缺失值。可用的选项有:
-backfill/bfill :最后一个有效观测值到下面的有效观测值。
-pad/ffill :用下面的有效观测值来填补。

| | how | 可用的选项是startend 。默认为end 。 | | normalize | 决定是否将输出指数重置为午夜。 | | fill_value | 这个参数是应用于缺失值(不是NaN值)的填充值。 |

在这个例子中,五(5)个随机整数在连续日(Daily Frequency)和工作日(Business Day Frequency)生成并显示。

代码 - 例1:

lst = np.random.randint(10,60, size=5)
idx = pd.date_range('1/16/2022', periods=5, freq='D')
series = pd.Series(lst, index= idx)
df = pd.DataFrame({'Series': series})
print(df)

result = df.asfreq(freq='B')
print(result)
  • 第[1]行在指定范围内生成五(5)个随机整数,并将其保存到lst
  • 第[2]行做了以下工作。
    • 基于五(5)天的开始日期创建一个索引。
    • 频率变为'D' (每日频率)。
    • 输出保存到idx
  • 第[3]行基于lstidx 变量创建一个系列。该输出保存到series
  • 第[4]行根据series 变量创建一个数据框架,并将其保存到df
  • 第[5]行将DataFrame输出到终端。
  • 第[6]行使用asfreq() 方法,将频率设置为'B' (营业日频率)。这个输出保存到result
  • 第[7]行将结果输出到终端。

输出结果:

df (连续5天)

系列
2022-01-1613
2022-01-1715
2022-01-1819
2022-01-1942
2022-01-2026

result (5个工作日 - M-F)

系列
2022-01-1715
2022-01-1819
2022-01-1942
2022-01-2026

2022年1月16日不显示在result 表中,因为它是星期天。

选择'B' 作为频率将忽略任何不在周一至周五之间的日期。

DataFrame asof()

asof() 方法根据where 参数中输入的日期,检索并返回DataFrame/系列(非NaN值)的最后一行。

这个方法的语法如下。

DataFrame.asof(where, subset=None)
参数参数描述
where这个参数是一个单一的日期或最后一行返回前的日期阵列。
subsetDataFrame列来检查NaN值。

在这个例子中,我们传递一个单一的日期。一个日期满足这个要求,并返回相应的值。

代码 - 例1:

nums = np.random.randint(1,50, size=7)
idx = pd.date_range('1/24/2022', periods=7, freq='D')
series = pd.Series(nums, index=idx)
print(series)

result = series.asof('1/27/2022')
print(result)

  • 第[1]行在指定的范围内生成七(7)个随机整数,并将其保存到nums
  • 第[2]行做了以下工作。
    • 基于五(5)天的开始日期创建一个索引。
    • 频率变为'D' (每日频率)。
    • 输出保存到idx
  • 第[3]行基于numsidx 变量创建一个系列。输出保存到series
  • 第[4]行将series 输出到终端。
  • 第[5]行检索与指定日期相关的单个值并保存到result
  • 第[6]行将结果输出到终端。

输出:

df (连续7天)

系列
2022-01-2410
2022-01-2534
2022-01-2631
2022-01-2725
2022-01-2835
2022-01-2941
2022-01-3049

result (2022-01-27)

频率: D, dtype: int32
25

在这个例子中,一个包含五(5)行的CSV文件被读入并保存到一个DataFrame。

代码 - 例2:

df = pd.read_csv('data.csv', parse_dates=['date'])
df.set_index('date', inplace=True)
print(df)

result = df['price'].asof(pd.DatetimeIndex(['2022-02-27 09:03:30', '2022-02-27 09:04:30']))
print(result)

  • 第[1]行从CSV文件创建了一个DataFrame,并使用以下方法解析了日期字段 [parse_dates()](https://blog.finxter.com/read-and-write-flat-files-with-pandas/).这个输出保存到df
  • 第[2]行在date 字段上设置DataFrame的索引和 [inplace=True](https://blog.finxter.com/python-inplace-or-operator-meaning/).
  • 第[3]行将DataFrame输出到终端。
  • 第[4]行根据指定的日期范围检索价格。输出保存到result
  • 第[5]行将结果输出到终端。

输出:

df

价格
日期
2022-02-27 09:01:008.12
2022-02-27 09:02:008.33
2022-02-27 09:03:008.36
2022-02-27 09:04:008.29
2022-02-27 09:05:008.13

result

2022-02-27 09:03:308.36
2022-02-27 09:04:308.29
名称:价格,dtype:float64

DataFrame shift()

shift() ,将指数按选定的周期数移动,并可选择设置时间频率。

这个方法的语法如下。

DataFrame.shift(periods=1, freq=None, axis=0, fill_value=NoDefault.no_default)
periods这个参数是要移动的周期数(正/负)。
freq点击这里查看频率,或者导航到一个IDE并运行。print(pd.tseries.offsets.__all__)
axis如果选择零(0)或指数,则应用于每一列。默认为0(列)。如果是零(1)或列,应用于每一行。
fill_value这个参数是新缺失值的填充值。默认值取决于dtype
- 数字:np.nan
-日期/时间/周期NaT
- 扩展dtypes:self.dtype.na_value


这个例子为三(3)个每日样本生成了七(5)个随机数。运行这段代码时,数据会移动一(1)个索引。移位后的数据被替换为NaN值。

df = pd.DataFrame({'Sample-1':  list(np.random.randint(0,100,size=5)),
                   'Sample-2':  list(np.random.randint(0,100,size=5)),
                   'Sample-3':  list(np.random.randint(0,100,size=5))},
                   index=pd.date_range('2020-01-01', '2020-01-05'))
print(df)

result1 = df.shift(periods=1)
print(result1)

result2 = df.shift(periods=1, fill_value=0)
print(result2)

  • 第[1]行做了以下工作。

    • 根据五(5)天的开始日期创建一个索引。

    • 频率改变为'D' (每日频率)。

    • 输出保存到idx

    • 创建一个有五(5)个随机整数的三(3)个样本的DataFrame。

    • 索引根据指定的日期范围创建。

    • 输出保存到df

  • 第[2]行将DataFrame输出到终端。

  • 第[3]行将数据移动了一(1)个周期。第一行的数据替换为NaN值。输出保存到result1

  • 第[4]行将result1 输出到终端。

  • 第[5]行将数据移位一(1)个周期,并将填充值设置为零(0)。输出保存为result2

  • 第[6]行将result2 输出到终端。

输出:

df

样本-1样本-2样本-3
2020-01-01188515
2020-01-0227664
2020-01-0378685
2020-01-0467718
2020-01-05942082

result1

样本-1样品-2样品-3
2020-01-01
2020-01-0218 .085.015.0
2020-01-0327 .066.04.0
2020-01-0478.068 .05.0
2020-01-056 .077.018.0

第一行的值现在显示NaN值。

原始数据框架的最后一行(df)不显示。

result2

样本-1样本-2样本-3
2020-01-01000
2020-01-0218 .085.015.0
2020-01-0327 .066.04.0
2020-01-0478.068 .05.0
2020-01-056 .077.018.0

result1 的NaN值变成了0(0)。

原始DataFrame (df)的最后一行不显示。

DataFrame slice_shift() & tshift()

这些方法已经不再使用了(从v1.2.0版本开始被废弃)。请使用上面显示的shift() 方法来代替。

DataFrame first_valid_index()

first_valid_index() 方法返回第一个非NA值的index ,如果不存在NA值,则返回None

这个方法的语法如下。

DataFrame.first_valid_index()

这个方法不包含任何参数。

在这个例子中,Rivers Clothing的定价表有一个问题。他们想找到第一个包含有效价格的索引(小号、中号、大号)。要做到这一点,请运行以下代码。

idx = ['Small', 'Mediun', 'Large']

df = pd.DataFrame({'Tops':     [np.nan, np.nan, np.nan],
                   'Tanks':    [np.nan, 13.45, 14.98],
                   'Pants':    [np.nan, 56.99, 94.87]}, index=idx)
print(df)

result = df.first_valid_index()
print(result)

  • 第[1]行为DataFrame创建一个索引并将其保存到idx
  • 第[2]行创建一个不完整库存价格的DataFrame,设置索引,并将其保存到df
  • 第[3]行将DataFrame输出到终端。
  • 第[4]行从DataFrame中检索出第一个有效的(非NA)值,并将索引保存到result
  • 第[5]行将结果输出到终端。

输出:

df

顶部短裤裤子
小号纳恩
中号13.4556.99
大号14.9894.87

结果Medium

第一个非NA值出现在Tanks类别下的Medium索引中。

DataFrame last_valid_index()

last_valid_index() 方法返回最后一个非NA值的index ,如果不存在NA值则返回None。

这个方法的语法如下。

DataFrame.last_valid_index()

这个方法不包含任何参数。

在这个例子中,Rivers Clothing的定价表有一个问题。他们想找到最后一个包含有效价格的索引(小号、中号、大号)。

要做到这一点,请运行以下代码。

idx = ['Small', 'Mediun', 'Large']

df = pd.DataFrame({'Tops':     [np.nan, np.nan, np.nan],
                   'Tanks':    [np.nan, 13.45, 14.98],
                   'Pants':    [np.nan, 56.99, 94.87]}, index=idx)
print(df)

result = df.last_valid_index()
print(result)

  • 第[1]行为DataFrame创建一个索引并将其保存到idx
  • 第[2]行创建一个不完整库存价格的DataFrame,设置索引,并将其保存到df
  • 第[3]行将数据框架输出到终端。
  • 第[4]行从DataFrame中检索最后一个有效(非NA)值,并将索引保存到result
  • 第[5]行将结果输出到终端。

输出:

df

顶部短裤裤子
小号纳恩
中号13.4556.99
大号14.9894.87

结果Large

最后一个非NA值出现在裤子类别下的Large索引中。