python - pandas 中按时间智能索引
问题描述
我有这样的数据框:
| Date | Device | Status |
| 1990/01 | 50 | ON |
| 1990/01 | 20 | ON |
| 1990/03 | 25 | ON |
| 1990/05 | 50 | OFF |
| 2000/01 | 20 | OFF |
基本上,我会在设备状态发生变化时记录它,但这不是周期性的,因此“日期”列不是“连续的”。我想用一些简单的逻辑在任何日期查询设备状态例如
df(device=50, date=1990/01) -> ON
- 简单的df(device=50, date=1990/02) -> ON
,设备 50 没有 1990/02,但是当设备设置为特定状态时,除非没有变化,否则它会一直保留在其中df(device=50, date=1990/05) -> OFF
df(device=50, date=2000/09) -> OFF
df(device=50, date=1900/01) -> OFF
,这是一个棘手的问题,在第一次打开之前,设备处于关闭状态
第二种情况具有不同的状态,但为了使问题简洁,我将保持不变。除了第 5 点外,行为完全相同。当我们假设设备在第一次登录 ON 状态之前也处于 ON 状态时。可能有更多状态,但决定设备状态的逻辑完全相同。
如何以熊猫的方式做到这一点?
解决方案
在我看来,必须为date_range
用于ed DataFramereindex
的select 定义所有可能的日期。s 首先被前向填充替换,所有第一个值被替换为:pivot
NaN
NaN
OFF
fillna
print (df)
Date Device Status
0 1990/01 50 ON
1 1990/01 20 ON
2 1990/03 25 ON
3 1990/05 50 OFF
4 1990/05 20 OFF <-changed for smaller output df
df['Date'] = pd.to_datetime(df['Date'])
rng = pd.date_range('1989-10-01', '1991-01-01', freq='MS')
df = df.pivot('Date','Device','Status').reindex(rng).ffill().fillna('OFF')
print (df)
Device 20 25 50
1989-10-01 OFF OFF OFF
1989-11-01 OFF OFF OFF
1989-12-01 OFF OFF OFF
1990-01-01 ON OFF ON
1990-02-01 ON OFF ON
1990-03-01 ON ON ON
1990-04-01 ON ON ON
1990-05-01 OFF ON OFF
1990-06-01 OFF ON OFF
1990-07-01 OFF ON OFF
1990-08-01 OFF ON OFF
1990-09-01 OFF ON OFF
1990-10-01 OFF ON OFF
1990-11-01 OFF ON OFF
1990-12-01 OFF ON OFF
1991-01-01 OFF ON OFF
dates
最后如果需要add的原始格式strftime
:
df.index = df.index.strftime('%Y/%m')
print (df)
Device 20 25 50
1989/10 OFF OFF OFF
1989/11 OFF OFF OFF
1989/12 OFF OFF OFF
1990/01 ON OFF ON
1990/02 ON OFF ON
1990/03 ON ON ON
1990/04 ON ON ON
1990/05 OFF ON OFF
1990/06 OFF ON OFF
1990/07 OFF ON OFF
1990/08 OFF ON OFF
1990/09 OFF ON OFF
1990/10 OFF ON OFF
1990/11 OFF ON OFF
1990/12 OFF ON OFF
1991/01 OFF ON OFF
编辑:
更通用的解决方案:
def get_status(df, device, check_date):
check_date = pd.to_datetime(check_date)
df['Date'] = pd.to_datetime(df['Date'])
rng = pd.date_range(df['Date'].min(), df['Date'].max(), freq='MS')
df = df.pivot('Date','Device','Status').reindex(rng).ffill().fillna('OFF')
#print (df)
if check_date < df.index.min():
return 'OFF'
elif check_date > df.index.max():
return df.loc[df.index[-1], device]
else:
return df.loc[check_date, device]
print (get_status(df, 50, '1990/01'))
#ON
print (get_status(df, 50, '1990/02'))
#ON
print (get_status(df, 50, '1990/05'))
#OFF
print (get_status(df, 50, '1990/09'))
#OFF
print (get_status(df, 50, '1900/01'))
#OFF
推荐阅读
- python - Python字符串列表,无法正确格式化
- ruby - 创建报告后的 rspec 挂钩
- android - 为什么谷歌 mlkit 条码扫描器会多次扫描同一个条码,甚至是其中的一部分
- hibernate - JPA问题的独特价值
- html - 打开一个简单的文本文件时出现奇怪的 SSL 问题,这怎么可能?
- c# - 具有动态单元格的 Unity Grid Layout Group
- javascript - 如何计算两个时间戳之间的总持续时间?Javascript
- java - 使用 JDBC 将数百万条记录插入表中
- r-markdown - 如何使用 RMarkdown 在 TeX 中按名称变量分组?
- sql - 嵌套一对多关系的唯一约束