【问题标题】:Trying to use Pandas to manipulate sensor time data尝试使用 Pandas 操作传感器时间数据
【发布时间】:2020-06-15 04:53:23
【问题描述】:

我正在尝试看看是否有办法使用 Pandas 进行以下计算:

我有一个表格,其中包含事件编号,后跟它们各自的开始和结束日期时间。

Event Number    Start            End
     1      6/1/2020 13:00  6/1/2020 13:30
     2      6/1/2020 17:45  6/1/2020 19:15
     3      6/4/2020 8:00   6/4/2020 9:10
     4      6/7/2020 11:00  6/7/2020 11:50

另外,我还有另一个表,其中包含每个传感器的原始时间索引数据

   Datetime    Sensor 1     Sensor 2    Sensor 3
6/1/2020 0:00     80           4           0
6/1/2020 0:01     80           5           0
6/1/2020 0:02     69           9           1
6/1/2020 0:03     72           8           0
6/1/2020 0:04     60           9           0
6/1/2020 0:05     76           3           0
6/1/2020 0:06     62           8           1
6/1/2020 0:07     80           8           0
6/1/2020 0:08     64           7           1

有没有一种方法可以运行该原始表并根据 START 和 END 时间戳裁剪该表?

我试图让决赛桌看起来像

  • 打开
  • 关闭
  • 分钟
  • 最大
  • 平均

这些日期之间的所有传感器。

我尝试过使用 for 循环但运气不佳,但它需要很长时间(+3M 行原始数据)。

有没有办法用 pandas 做到这一点?

提前感谢大家

编辑 1:添加了我的想法作为澄清的输出:

Event   Type    Sensor 1    Sensor 2    Sensor 3
  1     Open       60          5           1
  1     Close      69          8           0
  1     Max        78          8           1
  1     Min        59          4           0
  1     Mean       69          8           0.333
  2     Open       77          4           0
  2     Close      73          6           1
  2     Max        77          6           1
  2     Min        68          4           0
  2     Mean       74          6           0.667 
  3     Open       63          4           1
  3     Close      71          7           1
  3     Max        70          8           1
  3     Min        63          3           0
  3     Mean       65          4           1 

【问题讨论】:

  • 您能否提供一个理想最终结果的简短示例?所以我们可以可视化它的外观。
  • 我已将其添加为问题的编辑。谢谢。

标签: python pandas


【解决方案1】:

您可以使用pd.between 来获取您想要的传感器值,然后创建一个MultiIndexed Dataframe 来改进所获得数据的显示。您可以在这里找到有用的信息:how-to-check-where-datetime-is-in-between-two-datetimes-in-pandasconstructing-3d-pandas-dataframe。你可以试试这样的:

import pandas as pd
import numpy as np
import io
from statistics import mean

s_e = """Event Number    start            end
     1      6/1/2020 0:00  6/1/2020 0:02
     2      6/1/2020 0:05  6/1/2020 0:08"""
s_s = """   Datetime    Sensor 1     Sensor 2    Sensor 3
6/1/2020 0:00     80           4           0
6/1/2020 0:01     80           5           0
6/1/2020 0:02     69           9           1
6/1/2020 0:03     72           8           0
6/1/2020 0:04     60           9           0
6/1/2020 0:05     76           3           0
6/1/2020 0:06     62           8           1
6/1/2020 0:07     80           8           0
6/1/2020 0:08     64           7           1"""
events = pd.read_csv(io.StringIO(s_e), sep='\s\s+', parse_dates=[1,2], engine='python')
sensors = pd.read_csv(io.StringIO(s_s), sep='\s\s+', parse_dates=[0], engine='python')

#We create a dataframe with all values of ['Values','Open','Close','Min' ,'Max', 'Mean'] of each sensor
dfEveSen=pd.DataFrame()
pd.set_option('display.max_columns', None)
for sensor in sensors.columns[1:]:
    #we get the sensor values between start and end of each event 
    dfEveSen[sensor+'values']=[list(sensors[sensor][sensors.Datetime.between(start, end)].agg(list)) for start, end in zip(events['start'], events['end'])] 
    dfEveSen['first'+sensor]=dfEveSen[sensor+'values'].apply(lambda x: x[0])
    dfEveSen['last'+sensor]=dfEveSen[sensor+'values'].apply(lambda x: x[len(x)-1])
    dfEveSen['min'+sensor]=dfEveSen[sensor+'values'].apply(lambda x: min(x))
    dfEveSen['max'+sensor]=dfEveSen[sensor+'values'].apply(lambda x: max(x))
    dfEveSen['mean'+sensor]=dfEveSen[sensor+'values'].apply(lambda x: mean(x))



#We get the data of dfEveSen to create a MultiIndex dataframe
dataa=[dfEveSen[colum] for colum in dfEveSen.columns]
dataa=np.array(dataa)

#we define the the second indexed row ['Values','Open','Close','Min' ,'Max', 'Mean']
A = np.array( ['Values','Open','Close','Min' ,'Max', 'Mean']*3)

#we define the the first indexed row: ['Sensor 1', 'Sensor 2', 'Sensor 3']
B=np.repeat(sensors.columns[1:],6)

#We create the MultiIndex dataframe called sensorevent
sensorevent = pd.DataFrame(data=dataa.T, columns=pd.MultiIndex.from_tuples(zip(B,A)))
sensorevent.index.name = 'event'
sensorevent.index +=1
print(sensorevent)
#if you want to erase the column of values try this:
#sensorevent = sensorevent.drop('Values', axis=1, level=1)
#print(sensorevent)

输出:

                        Sensor 1                                  Sensor 2                              Sensor 3
                 Values Open Close Min Max     Mean        Values Open Close Min Max Mean        Values Open Close Min Max      Mean
event
1          [80, 80, 69]   80    69  69  80  76.3333     [4, 5, 9]    4     9   4   9    6     [0, 0, 1]    0     1   0   1  0.333333
2      [76, 62, 80, 64]   76    64  62  80     70.5  [3, 8, 8, 7]    3     7   3   8  6.5  [0, 1, 0, 1]    0     1   0   1       0.5

【讨论】:

    【解决方案2】:

    首先,我们在事件数据框 (df_e) 中从 StartEnd 创建一个 IntervalIndex。使用get_indexer,我们从df_e 获取事件编号,并将它们作为新列分配给传感器数据帧(df_s)。重要的是这里get_indexer 为缺失值返回-1,因此我们必须在df_e 的末尾添加一个对应的缺失事件行,以便iloc[-1] 返回这一行而不是原始的最后一行数据。然后我们只需按事件编号进行分组。

    idx = pd.IntervalIndex.from_arrays(df_e.Start, df_e.End, 'both')
    df_s.assign(event=df_e.append(pd.Series(dtype='Int64'), ignore_index=True).iloc[idx.get_indexer(df_s.Datetime), 0].values).groupby('event')[['Sensor 1', 'Sensor 2', 'Sensor 3']].agg(['first', 'last', 'min', 'max', 'mean'])
    

    例子:

    import pandas as pd
    import io
    
    s_e = """Event Number    Start            End
         1      6/1/2020 0:00  6/1/2020 0:02
         2      6/1/2020 0:05  6/1/2020 0:08"""
    s_s = """   Datetime    Sensor 1     Sensor 2    Sensor 3
    6/1/2020 0:00     80           4           0
    6/1/2020 0:01     80           5           0
    6/1/2020 0:02     69           9           1
    6/1/2020 0:03     72           8           0
    6/1/2020 0:04     60           9           0
    6/1/2020 0:05     76           3           0
    6/1/2020 0:06     62           8           1
    6/1/2020 0:07     80           8           0
    6/1/2020 0:08     64           7           1"""
    df_e = pd.read_csv(io.StringIO(s_e), sep='\s\s+', parse_dates=[1,2], engine='python')
    df_s = pd.read_csv(io.StringIO(s_s), sep='\s\s+', parse_dates=[0], engine='python')
    
    idx = pd.IntervalIndex.from_arrays(df_e.Start, df_e.End, 'both')
    df_s.assign(event=df_e.append(pd.Series(dtype='Int64'),ignore_index=True).iloc[idx.get_indexer(df_s.Datetime),0].values).groupby('event')[['Sensor 1', 'Sensor 2', 'Sensor 3']].agg(['first', 'last', 'min', 'max', 'mean'])
    

    结果:

          Sensor 1                         Sensor 2                   Sensor 3                       
             first last min max       mean    first last min max mean    first last min max      mean
    event                                                                                            
    1           80   69  69  80  76.333333        4    9   4   9  6.0        0    1   0   1  0.333333
    2           76   64  62  80  70.500000        3    7   3   8  6.5        0    1   0   1  0.500000
    


    该解决方案适用于大型数据集。对于 100K 行传感器数据和 5K 事件,需要 296 毫秒,而 pd.between 的另一个答案需要 16.6 秒。

    【讨论】:

    • 你知道为什么当从 Spyder 或 Jupyter Notebook 执行时会抛出 ValueError: no results 而从 cmd 执行时它会起作用吗?
    • @MrNobody33:不。我在 Spyder (python 3.8.2, pandas 1.0.4) 中运行示例时没有遇到任何错误。如果您对答案投了反对票,也许您可​​以解释一下为什么这个答案没有用?
    猜你喜欢
    • 2016-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-05
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    • 2017-05-02
    相关资源
    最近更新 更多