【问题标题】:Transform a Pandas series to be monotonic将 Pandas 系列转换为单调的
【发布时间】:2020-08-28 17:34:37
【问题描述】:

我正在寻找一种方法来删除破坏系列单调性的点。

例如

s = pd.Series([0,1,2,3,10,4,5,6])

s = pd.Series([0,1,2,3,-1,4,5,6])

我们会提取

s = pd.Series([0,1,2,3,4,5,6])

注意:我们假设第一个元素总是正确的。

【问题讨论】:

  • x=[0,1,2,3,10,4,5,6] s = pd.Series(x) 我们可以修改这样的列表吗?
  • 我不知道这个问题是否完全指定。对于[0,1,2,3,10,4,5,6],10 不会破坏单调性; 4(和 5、6)可以。为什么要删除 10?
  • 对于我的数据,意甲是能源消耗,所以我们知道它应该会增加。有时数据中存在错误,给出的点数不符合增加的趋势。这就是我们要删除的内容。

标签: python pandas series


【解决方案1】:

单调性可以是增加或减少,下面的函数将返回排除所有违反单调性的值。

但是,鉴于系列s = pd.Series([0,1,2,3,10,4,5,6])10 不会打破单调性条件,4, 5, 6 会打破您的问题。所以正确答案是0, 1, 2, 3, 10

import pandas as pd

s = pd.Series([0,1,2,3,10,4,5,6])

def to_monotonic_inc(s):
    return s[s >= s.cummax()]

def to_monotonic_dec(s):
    return s[s <= s.cummin()]

print(to_monotonic_inc(s))
print(to_monotonic_dec(s))

0, 1, 2, 3, 10 表示增加,0 表示减少。

也许你想找到最长的单调数组?因为这是一个完全不同的搜索问题。

----- 编辑-----

下面是在给定约束条件下使用普通 python 查找 最长 单调升序数组的简单方法:

def get_longeset_monotonic_asc(s):
    enumerated = sorted([(v, i) for i, v in enumerate(s) if v >= s[0]])[1:]
    output = [s[0]]
    last_index = 0
    for v, i in enumerated:
        if i > last_index:
            last_index = i
            output.append(v)

    return output

s1 = [0,1,2,3,10,4,5,6]
s2 = [0,1,2,3,-1,4,5,6]

print(get_longeset_monotonic_asc(s1))
print(get_longeset_monotonic_asc(s2))

'''
Output:

[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6]

'''

请注意,此解决方案涉及排序 O(nlog(n)) + 第二步 O(n)

【讨论】:

  • 就我的数据而言,意甲是能源消耗,所以我们知道它应该会增加。有时数据中存在错误,给出的点数不符合增加的趋势。这就是我们要删除的内容。在这种情况下是 10。
  • 我认为单调性不是你想要实现的正确方法。你的数据是线性的吗?多项式?我不会寻找单调性,而是执行一些多项式回归并丢弃异常值(离结果曲线太远的点)。
  • 数据只是在增加,因为它是一种能量测量,在线性回归后丢弃异常值会起作用,但看起来像是一个简单问题的高级解决方案。
  • 这不是那么简单,正如我在回答中所建议的那样,另一种方法可能是找到 longest 单调递增数组,这可能比计算线性回归有点棘手。我认为找到最长的单调数组是一个 O(n log(n)) 问题。
  • @melfaiz 我已经用第二种解决方案编辑了我的答案,该解决方案应该适用于您的用例。 (虽然可能不是最有效的)
【解决方案2】:

这是一种产生单调递增序列的方法:

import pandas as pd

# create data
s = pd.Series([1, 2, 3, 4, 5, 4, 3, 2, 3, 4, 5, 6, 7, 8])

# find max so far (i.e., running_max)
df = pd.concat([s.rename('orig'), 
                s.cummax().rename('running_max'),
               ], axis=1)

# are we at or above max so far?
df['keep?'] = (df['orig'] >= df['running_max'])

# filter out one or many points below max so far
df = df.loc[ df['keep?'], 'orig']

# verify that remaining points are monotonically increasing
assert pd.Index(df).is_monotonic_increasing

# print(df.drop_duplicates()) # eliminates ties
print(df)                     # keeps ties

0     1
1     2
2     3
3     4
4     5
10    5 # <-- same as previous value -- a tie
11    6
12    7
13    8
Name: orig, dtype: int64

您可以使用s.plot();df.plot(); 以图形方式查看

【讨论】:

    猜你喜欢
    • 2019-11-28
    • 2015-08-08
    • 2019-03-08
    • 2018-07-25
    • 2019-04-21
    • 1970-01-01
    • 2021-08-28
    • 2022-01-06
    • 1970-01-01
    相关资源
    最近更新 更多