将pandas DataFrame中的每小时时间序列分为特定日期和所有其他日期

时间:2019-09-02 09:42:54

标签: python pandas dataframe time-series

我在pandas DataFrame中有一个按时间排列的时间序列:

import pandas as pd
import numpy as np

idx = pd.date_range(freq="h", start="2018-01-01", periods=365*24)
df = pd.DataFrame({'value': np.random.rand(365*24)}, index=idx)

我有一个日期列表:

dates = ['2018-03-20', '2018-04-08', '2018-07-14']

我想最后得到两个DataFrame:一个仅包含这些日期的数据,另一个包含原始DataFrame中的所有数据,但不包括这些日期的所有数据。在这种情况下,我将有一个包含三天数据的数据框(用于dates中列出的日期)和一个包含362天数据的数据框(所有数据不包括那三天)。

在熊猫中做到这一点的最佳方法是什么?

我可以利用熊猫中基于字符串的基于日期时间的索引来分别提取每个日期,例如:

df[dates[0]]

并且我可以使用它来组合仅包含指定日期的DataFrame:

to_concat = [df[date] for date in dates]
just_dates = pd.concat(to_concat)

这虽然没有那么好,但是可以完成工作。

但是,我不知道如何从DataFrame中删除这些日期以获取所需的其他输出。正在执行:

df[~dates[0]]

给出一个TypeError: bad operand type for unary ~: 'str',我似乎无法让df.drop在这种情况下工作。

作为一种不错的,Pythonic的和类似“熊猫”的方式,您对此有何建议?

3 个答案:

答案 0 :(得分:3)

numpy.in1d创建布尔型掩码,将日期转换为字符串,或者用Index.isin创建测试成员资格:

m = np.in1d(df.index.date.astype(str), dates)

m = df.index.to_series().dt.date.astype(str).isin(dates)

DatetimeIndex.strftime表示字符串:

m = df.index.strftime('%Y-%m-%d').isin(dates)

另一个想法是通过DatetimeIndex.normalize删除时间-在输出中获得DatetimeIndex

m = df.index.normalize().isin(dates)
#alternative
#m = df.index.floor('d').isin(dates)

最后用boolean indexing过滤:

df1 = df[m]

第二个DataFrame反转掩码为~

df2 = df[~m]

print (df1)
                        value
2018-03-20 00:00:00  0.348010
2018-03-20 01:00:00  0.406394
2018-03-20 02:00:00  0.944569
2018-03-20 03:00:00  0.425583
2018-03-20 04:00:00  0.586190
                      ...
2018-07-14 19:00:00  0.710710
2018-07-14 20:00:00  0.403660
2018-07-14 21:00:00  0.949572
2018-07-14 22:00:00  0.629871
2018-07-14 23:00:00  0.363081

[72 rows x 1 columns]

答案 1 :(得分:2)

一种解决方法

df = df.reset_index()

with_date = df[df['index'].dt.date.astype(str).isin(dates)].set_index('index')
##use del with_date.index.name to remove the index name, if required

without_date = df[~df['index'].dt.date.astype(str).isin(dates)].set_index('index')

##with_date

                        value
index                        
2018-03-20 00:00:00  0.059623
2018-03-20 01:00:00  0.343513
...

##without_date
                        value
index                        
2018-01-01 00:00:00  0.087846
2018-01-01 01:00:00  0.481971
...

答案 2 :(得分:0)

另一种解决方法:

datetime格式保留日期,例如通过pd.Timestamp

dates_in_dt_format = [pd.Timestamp(date).date() for date in dates]

然后,仅保留索引日期不在该组中的行,例如:

df_without_dates = df.loc[[idx for idx in df.index if idx.date() not in dates_in_dt_format]]
df_with_dates = df.loc[[idx for idx in df.index if idx.date() in dates_in_dt_format]]

或使用熊猫来代替列表理解:

df_with_dates = df[df.index.to_series().apply(lambda x: pd.Timestamp(x).date()).isin(dates_in_dt_format)]
df_without_dates = df[~df.index.to_series().apply(lambda x: pd.Timestamp(x).date()).isin(dates_in_dt_format)]