【问题标题】:Finding contiguous, non-unique slices in Pandas series without iterating无需迭代即可在 Pandas 系列中查找连续的、非唯一的切片
【发布时间】:2016-05-31 04:58:00
【问题描述】:

我正在尝试解析我们制造过程的日志文件。大多数情况下,该过程是自动运行的,但偶尔,工程师需要切换到手动模式进行一些更改,然后再切换回反应堆软件的自动控制。当设置为手动模式时,日志文件将步骤记录为“MAN.OP”。而不是一个数字。下面是一个有代表性的例子。

steps = [1,2,2,'MAN.OP.','MAN.OP.',2,2,3,3,'MAN.OP.','MAN.OP.',4,4]
ser_orig = pd.Series(steps)

导致

0           1
1           2
2           2
3     MAN.OP.
4     MAN.OP.
5           2
6           2
7           3
8           3
9     MAN.OP.
10    MAN.OP.
11          4
12          4
dtype: object

我需要检测“MAN.OP”。并使它们彼此不同。在本例中,值 == 2 的两个区域在检测到手动模式部分后应该是一个区域,如下所示:

0                 1
1                 2
2                 2
3     Manual_Mode_0
4     Manual_Mode_0
5                 2
6                 2
7                 3
8                 3
9     Manual_Mode_1
10    Manual_Mode_1
11                4
12                4
dtype: object

我有代码迭代这个系列并在系列传递给我的对象时产生正确的结果。二传手是:

@step_series.setter
def step_series(self, ss):
    """
    On assignment, give the manual mode steps a unique name. Leave 
    the steps done on recipe the same.
    """
    manual_mode = "MAN.OP."
    new_manual_mode_text = "Manual_Mode_{}"
    counter = 0
    continuous = False
    for i in ss.index:
        if continuous and ss.at[i] != manual_mode:
            continuous = False
            counter += 1

        elif not continuous and ss.at[i] == manual_mode:
            continuous = True
            ss.at[i] = new_manual_mode_text.format(str(counter))

        elif continuous and ss.at[i] == manual_mode:
            ss.at[i] = new_manual_mode_text.format(str(counter))

    self._step_series = ss

但这会遍历整个数据帧,并且是我的代码中最慢的部分,而不是通过网络读取日志文件。

如何检测这些非唯一的部分并以唯一的方式重命名它们,而无需遍历整个系列?该系列是从较大的数据框中选择的列,因此如果需要添加额外的列是可以的。

对于我最终得到的完整答案:

@step_series.setter
def step_series(self, ss):
    pd.options.mode.chained_assignment = None
    manual_mode = "MAN.OP."
    new_manual_mode_text = "Manual_Mode_{}"

    newManOp = (ss=='MAN.OP.') & (ss != ss.shift())
    ss[ss == 'MAN.OP.'] = 'Manual_Mode_' + (newManOp.cumsum()-1).astype(str)

    self._step_series = ss

【问题讨论】:

    标签: python python-3.x pandas data-analysis


    【解决方案1】:

    这是一种方法:

    steps = [1,2,2,'MAN.OP.','MAN.OP.',2,2,3,3,'MAN.OP.','MAN.OP.',4,4]
    steps = pd.Series(steps)
    
    newManOp = (steps=='MAN.OP.') & (steps != steps.shift())
    steps[steps=='MAN.OP.'] += seq.cumsum().astype(str)
    
    >>> steps
    0            1
    1            2
    2            2
    3     MAN.OP.1
    4     MAN.OP.1
    5            2
    6            2
    7            3
    8            3
    9     MAN.OP.2
    10    MAN.OP.2
    11           4
    12           4
    dtype: object
    

    要获得您列出的确切格式(从零开始而不是一,并从“MAN.OP.”更改为“Manual_mode_”),只需调整最后一行:

    steps[steps=='MAN.OP.'] = 'Manual_Mode_' + (seq.cumsum()-1).astype(str)
    
    >>> steps
    0                 1
    1                 2
    2                 2
    3     Manual_Mode_0
    4     Manual_Mode_0
    5                 2
    6                 2
    7                 3
    8                 3
    9     Manual_Mode_1
    10    Manual_Mode_1
    11                4
    12                4
    dtype: object
    

    a pandas enhancement request 用于连续 groupby,这将使此类任务更简单。

    【讨论】:

    • 哇,太棒了!遍历数据帧的三个测试的平均值为 2.234 秒。更改为您建议的方式后,我的 3 测试平均值下降到 0.159 秒。感谢您的帮助。
    【解决方案2】:

    matplotlib 中有一个 s 函数,它接受一个布尔数组并返回一个 (start, end) 对的列表。每对代表一个连续区域,其中输入为True

    import matplotlib.mlab as mlab
    regions = mlab.contiguous_regions(ser_orig == manual_mode)
    for i, (start, end) in enumerate(regions):
        ser_orig[start:end] = new_manual_mode_text.format(i)
    ser_orig
    
    0                 1
    1                 2
    2                 2
    3     Manual_Mode_0
    4     Manual_Mode_0
    5                 2
    6                 2
    7                 3
    8                 3
    9     Manual_Mode_1
    10    Manual_Mode_1
    11                4
    12                4
    dtype: object
    

    【讨论】:

    • 感谢您的建议,对于非熊猫功能,我会记住此功能。
    猜你喜欢
    • 2017-10-22
    • 1970-01-01
    • 2019-10-09
    • 1970-01-01
    • 2017-10-20
    • 1970-01-01
    • 1970-01-01
    • 2017-08-09
    • 1970-01-01
    相关资源
    最近更新 更多