pandas Python中的“Cumcount with Reset”和“Keep Last with Reset”

gwo2fgha  于 2023-05-21  发布在  Python
关注(0)|答案(4)|浏览(97)

我有一个关于这个prior StackOverflow question的后续问题。
假设我有以下NumPy数组:

import numpy as np
v = np.array([
  0, 0, 0, 1, 3, 3, 1, 1, 1, 1, 1, 0, 2, 3, 2, 1, 1, 0, 0, 1, 3, 3,
  3, 2, 0, 0, 0, 0, 1, 1, 1, 2, 1, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0,
  1, 1, 1, 0, 0, 0, 1, 2, 2, 1, 0, 0, 1, 1, 1, 1, 1, 2, 1, 1, 2, 0,
  0, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2,
  2, 0, 0, 0, 0, 1])

我试图获得所有重复元素序列及其起始索引的列表。我的直觉是,使用Pandas是实现这一目标的最直接的方法。
使用前面引用的StackOverflow答案,我写了以下内容:

import pandas as pd
df = pd.DataFrame(v, columns=['digit'])
df["seq_len"] = df.groupby(
    (df["digit"] != df["digit"].shift()).cumsum()
    )["digit"].cumcount()+1

产生结果:

digit  seq_len
0       0        1
1       0        2
2       0        3
3       1        1
4       3        1
..    ...      ...
89      0        1
90      0        2
91      0        3
92      0        4
93      1        1

我需要做的最后一件事是删除“digit”列沿着的重复项,以便保留最后一个“seq_len”值。通常,你可以使用Pandas duplicateddrop_duplicates,但是这些函数不会沿着列进行任何重置。
想要的是:

>>> df.drop_duplicates(subset='digit', keep='last')
    digit  seq_len
22      3        3
88      2        3
92      0        4
93      1        1

我想要的是:

>>> magic_function(df)
    digit  seq_len
2       0        3
3       1        1
5       3        2
10      1        5
..    ...      ...
88      2        3
92      0        4
93      1        1

当然,如果我执行“index-seq_len + 1”,我可以获得真正的起始索引,例如,

index    digit  seq_len
0            0        3
3            1        1
4            3        2
6            1        5
..         ...      ...
86           2        3
89           0        4
92           1        1

因此,无论如何,寻找任何关于高效magic_function()的建议来完成上述任务。感谢所有的帮助!

5cg8jx4n

5cg8jx4n1#

你可以使用GroupBy.applyboolean indexing

m = df["digit"].ne(df["digit"].shift())
grp = df.groupby(m.cumsum(), group_keys=False)

df["seq_len"] = grp["digit"].cumcount().add(1)

out = grp.apply(lambda g: g.loc[~g["digit"].duplicated(keep="last")])

输出:

print(out)

    digit  seq_len
2       0        3
3       1        1
5       3        2
10      1        5
11      0        1
..    ...      ...
83      0        7
85      1        2
88      2        3
92      0        4
93      1        1

[43 rows x 2 columns]
5uzkadbs

5uzkadbs2#

虽然不太好,但这似乎是可行的:

v = np.array([
  0, 0, 0, 1, 3, 3, 1, 1, 1, 1, 1, 0, 2, 3, 2, 1, 1, 0, 0, 1, 3, 3,
  3, 2, 0, 0, 0, 0, 1, 1, 1, 2, 1, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0,
  1, 1, 1, 0, 0, 0, 1, 2, 2, 1, 0, 0, 1, 1, 1, 1, 1, 2, 1, 1, 2, 0,
  0, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2,
  2, 0, 0, 0, 0, 1])

df = pd.DataFrame(v, columns=['digit'])
df["seq_len"] = df.groupby((df["digit"] != df["digit"].shift()).cumsum())["digit"].cumcount()+1

# The new stuff:
s = df["digit"].diff()[1:] != 0
df.loc[list(s[s].index - 1) + [len(df) - 1]]
nkkqxpd9

nkkqxpd93#

您可以使用内置的groupby函数first/lastsize。对于最后一个索引,我使用了一个简单的lambda,但我感觉有一种更直接的方法我忘记了。

df['digit'].groupby(
    df["digit"].ne(df["digit"].shift()).cumsum(),
    ).agg(
        last_index=lambda x: x.index[-1],
        digit='first',
        seq_len='size',
    ).set_index('last_index')
digit  seq_len
last_index                
2               0        3
3               1        1
5               3        2
10              1        5
...           ...      ...
85              1        2
88              2        3
92              0        4
93              1        1

[43 rows x 2 columns]
woobm2wo

woobm2wo4#

这也应该起作用:

(df.assign(seq_len = df.groupby(df['digit'].diff().ne(0).cumsum())['digit'].transform('size'))
.loc[df['digit'].iloc[::-1].diff().ne(0)])

m = df['digit'].diff().ne(0).cumsum()
df.assign(seq_len = df.groupby(m)['digit'].cumcount()+1).groupby(m).tail(1)

m = df['digit'].diff().ne(0).cumsum()
df.assign(seq_len = df.groupby(m)['digit'].cumcount()+1).loc[lambda x: x.groupby(m)['seq_len'].idxmax()]

输出:

digit  seq_len
2       0        3
3       1        1
5       3        2
10      1        5
11      0        1
12      2        1
13      3        1
14      2        1
16      1        2
18      0        2
19      1        1
22      3        3
23      2        1
27      0        4
30      1        3
31      2        1
32      1        1
37      0        5
38      1        1
40      2        2
41      1        1
43      0        2
46      1        3
49      0        3
...
85      1        2
88      2        3
92      0        4
93      1        1

相关问题