有没有更简单的方法来使 pandas.Series 单调递增或递减?

3

我希望能快速找到一种方法来使 pandas DataFrame 在 x 轴上单调。

我的当前解决方案如下:

def make_monotonic(df, cols=None):
    """make df monotonic"""
    if not cols:
        cols = df.columns

    mycol = "_maximum"

    dfm = df.copy()
    for col in cols:
        dfm[mycol] = np.maximum.accumulate(dfm[col])
        dfm.drop_duplicates([mycol], keep="first", inplace=True)
    del dfm[mycol]
    return dfm

n=21
np.random.seed(21)
x = np.linspace(0,np.pi,n)
dx = .5 * (np.random.random(n)-.5)
df = pd.DataFrame.from_dict({"x0":x, "x":x+dx, "y":np.sin(x)})
dfm = make_monotonic(df, cols=["x"])

使列x在"x"中单调 使列x在"x"中单调

我想生成一个函数y = f(x)

            x         x0               y
0   -0.676913   0.000000    0.000000e+00
1   -0.002176   0.314159    3.090170e-01
2   0.959768    0.628319    5.877853e-01
3   0.224902    0.942478    8.090170e-01
4   0.815521    1.256637    9.510565e-01
5   0.896956    1.570796    1.000000e+00
6   1.588363    1.884956    9.510565e-01
7   2.444980    2.199115    8.090170e-01
8   2.225446    2.513274    5.877853e-01
9   2.952820    2.827433    3.090170e-01
10  2.495949    3.141593    1.224647e-16

为了

            x         x0           y
0   -0.676913   0.000000    0.000000
1   -0.002176   0.314159    0.309017
2   0.959768    0.628319    0.587785
6   1.588363    1.884956    0.951057
7   2.444980    2.199115    0.809017
9   2.952820    2.827433    0.309017

一个序列被称为单调的,它意味着什么? - ℕʘʘḆḽḘ
“monotonic in x” 的意思是每一行中的 x 值应该始终大于前一行中的 x 值。 - steller
你的意思是只需要对数据进行排序吗? - ℕʘʘḆḽḘ
不,数据框已经排序了(索引!)。我会跳过破坏单调性的行。我只需要升序的 x 值,例如在 np.interp 中使用该列。 - steller
1个回答

12

使用 df.cummax() 实际上是一种非常简单的方法来实现这个。

cols = ['your', 'columns']
mon_inc = (df[cols].cummax().diff().fillna(.1) > 0).all(axis=1)
df[mon_inc]

以下是旧的逻辑:

您可以使用diff方法在行之间不断取差,直到所有值都大于0。

while True:
    mon_inc = df['x'].diff().fillna(0) >= 0
    if mon_inc.all():
        break
    df = df[mon_inc]

还有一个可以进行任意列数的函数

def make_monotonic(df, cols=None):
    if cols is None:
        cols = df.columns

    df1 = df.copy()[cols]

    while True:
        mon_inc = (df1.diff().fillna(0) >= 0).all(axis=1)
        if mon_inc.all():
            break
        df1 = df1[mon_inc]
    return df1

1
感谢您的快速回答。解决方案看起来不错。对于我的用例,循环次数不是很多。 - steller
1
哇!太棒了;-)(对自己说:RTFM…)不幸的是,由于没有分数,我无法为你投票,但我稍后会回来的;-) - steller
太棒了。对于一个列,不一定是数字,它可以简化为 df[df.col == df.col.cummax()]。 - JohnLittle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接