【问题标题】:Pandas series between two date time files两个日期时间文件之间的熊猫系列
【发布时间】:2017-09-30 16:44:52
【问题描述】:

我的问题是关于使用 Pandas 时间序列。

我有一个文件(Spots),其中包含一个月数据的熊猫时间序列,范围为 7.5 秒。 示例:

2016-11-01 00:00:00,0
2016-11-01 00:00:07.500000,1
2016-11-01 00:00:15,2
2016-11-01 00:00:22.500000,3
2016-11-01 00:00:30,4

另一个文件(目标)只有时间信息。

例子:

2016-11-01 00:00:05
2016-11-01 00:00:07
2016-11-01 00:00:23
2016-11-01 00:00:25

我想查看目标日期时间属于哪个时间点: 上面例子中的输出:

2016-11-01 00:00:00,0 '\t' count of targets in this spot = 2
2016-11-01 00:00:07.500000,1 '\t' count of targets in this spot = 0
2016-11-01 00:00:15,2 '\t' count of targets in this spot = 0
2016-11-01 00:00:22.500000,3 '\t' count of targets in this spot = 0
2016-11-01 00:00:30,4 '\t' count of targets in this spot = 2

提前非常感谢您。如果这很清楚,请告诉我,否则我可以尝试解释更多。

【问题讨论】:

  • 第一行如何在那个位置有 2 个目标?看起来应该是 0。除非您将目标四舍五入到最近的点?更清楚地了解结果背后的逻辑会有所帮助。

标签: python-2.7 pandas data-science


【解决方案1】:

这是我的建议。首先,将另一列添加到目标框架。这样可以在未来合并后识别目标:

target['T'] = 1

连接目标和点并按时间排序:

both = pd.concat([spots,target]).sort_values(0)
#                        0    1    T
#0 2016-11-01 00:00:00.000  0.0  NaN
#0 2016-11-01 00:00:05.000  NaN  1.0
#1 2016-11-01 00:00:07.000  NaN  1.0
#1 2016-11-01 00:00:07.500  1.0  NaN
#2 2016-11-01 00:00:15.000  2.0  NaN
#3 2016-11-01 00:00:22.500  3.0  NaN
#2 2016-11-01 00:00:23.000  NaN  1.0
#3 2016-11-01 00:00:25.000  NaN  1.0
#4 2016-11-01 00:00:30.000  4.0  NaN

向前填充点 ID:

both[1] = both[1].fillna(method='ffill').astype(int)
#                        0  1    T
#0 2016-11-01 00:00:00.000  0  NaN
#0 2016-11-01 00:00:05.000  0  1.0
#1 2016-11-01 00:00:07.000  0  1.0
#1 2016-11-01 00:00:07.500  1  NaN
#2 2016-11-01 00:00:15.000  2  NaN
#3 2016-11-01 00:00:22.500  3  NaN
#2 2016-11-01 00:00:23.000  3  1.0
#3 2016-11-01 00:00:25.000  3  1.0
#4 2016-11-01 00:00:30.000  4  NaN

选择原始目标行和列:

both[both['T']==1][[0,1]]
#                    0  1
#0 2016-11-01 00:00:05  0
#1 2016-11-01 00:00:07  0
#2 2016-11-01 00:00:23  3
#3 2016-11-01 00:00:25  3

如果你想统计点中的目标,请使用groupby()

both.groupby(1).count()['T']
#1
#0    2
#1    0
#2    0
#3    2
#4    0

【讨论】:

    【解决方案2】:

    让我们使用merge_orderedfillnagroupby

    输入:

    df_spots
    
                         Date  Value
    0 2016-11-01 00:00:00.000      0
    1 2016-11-01 00:00:07.500      1
    2 2016-11-01 00:00:15.000      2
    3 2016-11-01 00:00:22.500      3
    4 2016-11-01 00:00:30.000      4
    
    df_target
    
                     Date
    0 2016-11-01 00:00:05
    1 2016-11-01 00:00:07
    2 2016-11-01 00:00:23
    3 2016-11-01 00:00:25
    

    代码:

    merged_df = pd.merge_ordered(df_spots, df_target, on = 'Date')
    df_out = (merged_df.groupby(by=merged_df['Value']
                   .fillna(method='ffill'), as_index=False)
                   .agg({'Date':'first',
                         'Value':{'first':'first','count':lambda x:len(x)-1}}))
    

    输出:

    df_out
    
                         Date Value      
                        first first count
    0 2016-11-01 00:00:00.000   0.0   2.0
    1 2016-11-01 00:00:07.500   1.0   0.0
    2 2016-11-01 00:00:15.000   2.0   0.0
    3 2016-11-01 00:00:22.500   3.0   2.0
    4 2016-11-01 00:00:30.000   4.0   0.0
    

    【讨论】:

    • 哇!非常感谢大家!我不知道有这么多漂亮和优雅的方式来使用 Panda。今晚我将尝试所有这些,让你们都知道它是怎么回事。非常感谢!
    • 嗨@Scott Boston,我尝试了你的方法,但我没有得到计数,而是它只是匹配我认为是行号的第一列?首先,我不得不将 merge_ordered 更改为 order_merged,但即便如此,我也得到了相同的结果。我注意到在 merge_df 中,第二个数据框中没有“值”,所以“值”上的追随者仍然有效吗?你能帮我理解我可能做错了什么吗?此外,当我打印我的 df_out 时,我首先得到第一个计数,而不是第一个计数。
    • 你有什么版本的熊猫?我用的是最新的 0.19.2,我想你可能用的是早期版本。
    • 是的,我考虑过这一点并升级了 pandas 并运行它,它运行良好。谢谢大家的帮助
    【解决方案3】:

    结合使用np.searchsortedpd.value_counts 以及其他一些内容。

    idx = Spots.index.to_series()
    i = idx.values
    t = Target.Date.values
    m = pd.value_counts(i[i.searchsorted(t) - 1]).to_dict()
    Spots.assign(TargetCount=idx.map(lambda x: m.get(x, 0)))
    
                             Value  TargetCount
    Date                                       
    2016-11-01 00:00:00.000      0            2
    2016-11-01 00:00:07.500      1            0
    2016-11-01 00:00:15.000      2            0
    2016-11-01 00:00:22.500      3            2
    2016-11-01 00:00:30.000      4            0
    

    工作原理

    • idxSpots 的索引变成了pd.Series,因为我想稍后使用pd.Series.map
    • i 是底层 numpy 数组,我将使用它执行 searchsorted 操作
    • ti 相同...searchsorted 的一部分
    • searchsorted 将遍历右数组中的每个元素,并找到该元素相对于右数组的插入位置。此信息可用于查找元素所属的“bin”。然后我减去一个以与适当的索引对齐
    • 然后我执行pd.value_counts 来计算它们
    • 使用map 构建一个新列。

    设置

    from io import StringIO
    import pandas as pd
    
    tx1 = """2016-11-01 00:00:00,0
    2016-11-01 00:00:07.500000,1
    2016-11-01 00:00:15,2
    2016-11-01 00:00:22.500000,3
    2016-11-01 00:00:30,4"""
    
    tx2 = """2016-11-01 00:00:05
    2016-11-01 00:00:07
    2016-11-01 00:00:23
    2016-11-01 00:00:25"""
    
    Spots = pd.read_csv(StringIO(tx1), parse_dates=[0], index_col=0, names=['Date', 'Value'])
    
    Target = pd.read_csv(StringIO(tx2), parse_dates=[0], names=['Date'])
    

    【讨论】:

      【解决方案4】:

      使用熊猫merge_asof (注意,所有时间值都必须排序 - 可能必须先排序):

      设置~~~~~~~~

      import pandas as pd    
      
      # make date_range with 1 sec interval (fake targets)
      rng = pd.date_range('2016-11-01', periods=100, freq='S')
      
      # resample to make 7.5 sec intervals (fake spot bins)
      ts = pd.Series(np.arange(100), index=rng)
      ts_vals = ts.resample('7500L').asfreq().index
      
      df_spots = pd.DataFrame({'spot': np.arange(len(ts_vals)), 'bin': ts_vals})
      df_spots.head()
                            bin  spot
      0 2016-11-01 00:00:00.000  0   
      1 2016-11-01 00:00:07.500  1   
      2 2016-11-01 00:00:15.000  2   
      3 2016-11-01 00:00:22.500  3   
      4 2016-11-01 00:00:30.000  4 
      
      df_targets = pd.DataFrame(rng, columns=['tgt'])
      df_targets.head()
      
                        tgt
      0 2016-11-01 00:00:00
      1 2016-11-01 00:00:01
      2 2016-11-01 00:00:02
      3 2016-11-01 00:00:03
      4 2016-11-01 00:00:04
      

      解决办法~~~~~~~

      # this will produce spot membership for targets
      df = pd.merge_asof(df_targets, df_spots, left_on='tgt', right_on='bin')
      df.head()
                        tgt                     bin  spot
      0 2016-11-01 00:00:00 2016-11-01 00:00:00.000  0   
      1 2016-11-01 00:00:01 2016-11-01 00:00:00.000  0   
      2 2016-11-01 00:00:02 2016-11-01 00:00:00.000  0   
      3 2016-11-01 00:00:03 2016-11-01 00:00:00.000  0   
      4 2016-11-01 00:00:04 2016-11-01 00:00:00.000  0   
      5 2016-11-01 00:00:05 2016-11-01 00:00:00.000  0   
      6 2016-11-01 00:00:06 2016-11-01 00:00:00.000  0   
      7 2016-11-01 00:00:07 2016-11-01 00:00:00.000  0   
      8 2016-11-01 00:00:08 2016-11-01 00:00:07.500  1   
      9 2016-11-01 00:00:09 2016-11-01 00:00:07.500  1   
      
      # for spot counts...
      df_counts = pd.DataFrame(df.groupby('bin')['spot'].count())
      df_counts.head()
                               spot
      bin                          
      2016-11-01 00:00:00.000  8   
      2016-11-01 00:00:07.500  7   
      2016-11-01 00:00:15.000  8   
      2016-11-01 00:00:22.500  7   
      2016-11-01 00:00:30.000  8   
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-05
        • 1970-01-01
        • 2020-10-19
        • 2021-12-29
        • 1970-01-01
        • 2019-02-19
        • 1970-01-01
        • 2017-06-16
        相关资源
        最近更新 更多