Python 使用重采样缩小包含布尔数据的序列

Python 使用重采样缩小包含布尔数据的序列,python,csv,numpy,pandas,Python,Csv,Numpy,Pandas,我有一个大的时间序列数据框,在单独的列中包含数字和布尔数据。我正在尝试将数据采样时间从1分钟缩短到15分钟。布尔列是系统状态,我正在努力解决如何减少对它们的采样并仍然保留任何故障。目前,我的重采样使用的是last,因此将忽略除最后一行以外的任何行上发生的任何系统故障 我希望它做的是:如果在15分钟系列中的任何一行上出现“fault”,那么重采样后产生的时间戳将读取“fault”,否则将读取“ok” 我知道解决方案存在于重采样的how=',但因为我对numpy和pandas是新手,所以我不知道该用

我有一个大的时间序列数据框,在单独的列中包含数字和布尔数据。我正在尝试将数据采样时间从1分钟缩短到15分钟。布尔列是系统状态,我正在努力解决如何减少对它们的采样并仍然保留任何故障。目前,我的重采样使用的是
last
,因此将忽略除最后一行以外的任何行上发生的任何系统故障

我希望它做的是:如果在15分钟系列中的任何一行上出现“fault”,那么重采样后产生的时间戳将读取“fault”,否则将读取“ok”

我知道解决方案存在于重采样的
how='
,但因为我对numpy和pandas是新手,所以我不知道该用什么

我的代码:

import pandas as pd

# Reads .csv, combines Date and Time columns into Timestamp, sets Timestamp as index
df = pd.read_csv('data.csv', parse_dates = {'Timestamp' : ['Date', 'Time']}, index_col = 'Timestamp')

# Fixing any incomplete data and interpolating any numerical gaps 
index = pd.date_range(freq='1min', start=df.first_valid_index(), end=df.last_valid_index())
df_clean = df.reindex(set(df.index).union(index))
for col in df_clean:
    df_clean[col] = df_clean[col].interpolate('time').ix[index]

# Downsampling numerical data 
df_avg = df_clean.resample('15min', how='mean')

# Downsampling boolean data separately 
df_avg['alarm1']=df_clean['alarm1'].resample('15min', how='last')

# Fix for missing index name
df_avg.index.name = 'Timestamp'

# Adding date and time columns back to dataframe
df_avg.reset_index(level=0, inplace=True)
df_avg['Date'] = df_avg['Timestamp'].apply(lambda x: x.strftime('%Y/%m/%d'))
df_avg['Time'] = df_avg['Timestamp'].apply(lambda x: x.strftime('%H:%M:%S'))

# Write new .csv 
df_avg[['Date','Time','A','B','C','alarm1']].to_csv('out.csv', index=False)

docstring说明了
如何
应该是一个字符串,但实际上它也可以是一个可调用的字符串

如果“alarm1”列为布尔值,则可以使用
how=any
(或
how=np.any
any
逻辑上将
每个时间段中的值,因此如果时间段中的任何值为真,则下采样序列中的值将为真

这里有一个例子

首先,设置随机种子并创建一系列布尔值

In [101]: np.random.seed(123456)

In [102]: rng = pd.date_range('1/1/2011', periods=25, freq='1min')

In [103]: ts = pd.Series(np.random.rand(len(rng)) > 0.85, index=rng)

In [104]: ts
Out[104]: 
2011-01-01 00:00:00    False
2011-01-01 00:01:00     True
2011-01-01 00:02:00    False
2011-01-01 00:03:00     True
2011-01-01 00:04:00    False
2011-01-01 00:05:00    False
2011-01-01 00:06:00    False
2011-01-01 00:07:00    False
2011-01-01 00:08:00    False
2011-01-01 00:09:00    False
2011-01-01 00:10:00    False
2011-01-01 00:11:00    False
2011-01-01 00:12:00    False
2011-01-01 00:13:00     True
2011-01-01 00:14:00    False
2011-01-01 00:15:00    False
2011-01-01 00:16:00    False
2011-01-01 00:17:00    False
2011-01-01 00:18:00    False
2011-01-01 00:19:00    False
2011-01-01 00:20:00     True
2011-01-01 00:21:00    False
2011-01-01 00:22:00    False
2011-01-01 00:23:00    False
2011-01-01 00:24:00    False
Freq: T, dtype: bool
使用
重新采样
将频率转换为5分钟。使用
how=np.any
在逻辑上
时间段中的值

In [105]: ds = ts.resample('5min', how=np.any)

In [106]: ds
Out[106]: 
2011-01-01 00:00:00     True
2011-01-01 00:05:00    False
2011-01-01 00:10:00     True
2011-01-01 00:15:00    False
2011-01-01 00:20:00     True
Freq: 5T, dtype: bool
您还可以对这些值求和,这将为您提供每个时间段中的报警数:

In [107]: ts.resample('5min', how=sum)
Out[107]: 
2011-01-01 00:00:00    2
2011-01-01 00:05:00    0
2011-01-01 00:10:00    1
2011-01-01 00:15:00    0
2011-01-01 00:20:00    1
Freq: 5T, dtype: float64

更新:

如注释中所述,如果
alarm1
列包含字符串
'YES'
'NO'
,有几种方法可以处理它。例如,您可以简单地将值转换为布尔值(例如,
tsbool=ts==“YES”
),并使用上述技术

或者,您可以编写一个自定义聚合函数,例如

def func(faults):
    return 'YES' if np.any(faults == 'YES') else 'NO'
并将其作为
resample
how
参数。这里有一个例子

首先,创建一个包含字符串“YES”和“NO”的序列

In [60]: rng = pd.date_range('1/1/2011', periods=25, freq='1min')

In [61]: yn = np.array(['NO', 'YES'])

In [62]: ts = pd.Series(yn[(np.random.rand(len(rng)) > 0.85).astype(int)], index=rng)

In [63]: ts
Out[63]: 
2011-01-01 00:00:00     NO
2011-01-01 00:01:00     NO
2011-01-01 00:02:00     NO
2011-01-01 00:03:00     NO
2011-01-01 00:04:00    YES
2011-01-01 00:05:00    YES
2011-01-01 00:06:00     NO
2011-01-01 00:07:00    YES
2011-01-01 00:08:00     NO
2011-01-01 00:09:00     NO
2011-01-01 00:10:00     NO
2011-01-01 00:11:00     NO
2011-01-01 00:12:00     NO
2011-01-01 00:13:00     NO
2011-01-01 00:14:00     NO
2011-01-01 00:15:00     NO
2011-01-01 00:16:00    YES
2011-01-01 00:17:00     NO
2011-01-01 00:18:00     NO
2011-01-01 00:19:00     NO
2011-01-01 00:20:00     NO
2011-01-01 00:21:00     NO
2011-01-01 00:22:00     NO
2011-01-01 00:23:00     NO
2011-01-01 00:24:00     NO
Freq: T, dtype: object
定义将“是”和“否”字符串数组缩减为单个字符串的函数

In [64]: def func(alarms):
   ....:     return 'YES' if np.any(alarms == 'YES') else 'NO'
   ....: 
使用该功能重新采样
ts

In [65]: ds = ts.resample('5min', how=func)

In [66]: ds
Out[66]: 
2011-01-01 00:00:00    YES
2011-01-01 00:05:00    YES
2011-01-01 00:10:00     NO
2011-01-01 00:15:00    YES
2011-01-01 00:20:00     NO
Freq: 5T, dtype: object

看来我说错了。我的故障列包含有/没有数据,Python似乎不被认为是布尔型的。有没有办法用y/n而不是t/f来解析我的fault列?我定义了一个新函数,它工作得很好!非常感谢。我有一个很大的数据帧,发现将“sum”与不等式函数一起使用要快得多:
df.resample('15min',how='sum')>=1