pandas 有效地过滤掉重复列的最后一行

edqdpe6u  于 2023-03-11  发布在  其他
关注(0)|答案(6)|浏览(175)

我需要过滤掉col2 = 3所在的最后一行,但保留 Dataframe 的其余部分。
我可以这样做,同时保持相对于索引的顺序:

import pandas

d = {
     'col1': [0, 1, 2, 3, 3, 3, 3, 4, 5, 6],
     'col2': [0, 11, 21, 31, 32, 33, 34, 41, 51, 61]
    }

df = pandas.DataFrame(d)
df2 = df[df['col1'] != 3]
df3 = df[df['col1'] == 3].iloc[:-1]

pandas.concat([df2,df3]).sort_index()
col1 col2
0   0    0
1   1    11
2   2    21
3   3    31
4   3    32
5   3    33
7   4    41
8   5    51
9   6    61

但是对于更大的 Dataframe ,执行此操作的开销会逐渐增加。
有没有更有效的方法?

更新

根据到目前为止提供的答案,以下是结果:
一个二个一个一个

irtuqstp

irtuqstp1#

也可能:

out = df.loc[ df["col1"].ne(3) | df["col1"].duplicated(keep="last") ]

输出:

col1  col2
0     0     0
1     1    11
2     2    21
3     3    31
4     3    32
5     3    33
7     4    41
8     5    51
9     6    61
w41d8nur

w41d8nur2#

您可以用途:

>>> df.drop(df['col1'].where(df['col1'].eq(3)).last_valid_index())
   col1  col2
0     0     0
1     1    11
2     2    21
3     3    31
4     3    32
5     3    33
7     4    41
8     5    51
9     6    61
iq0todco

iq0todco3#

您可以用途:

# get the last index of 3 in col1
idx = df.loc[::-1, 'col1'].eq(3).idxmax()

# if there was no 3 in col1, this would give a false positive
# idxmax would return the last non-3 instead
# ensure that we drop the correct row
if df.loc[idx, 'col1'] == 3:
    df = df.drop(idx)
  • 注意:如果您已经知道3在col 1中,那么简单的df = df.drop(idx)就足够了。*

输出:

col1  col2
0     0     0
1     1    11
2     2    21
3     3    31
4     3    32
5     3    33
7     4    41
8     5    51
9     6    61
计时比较

Dataframe 大小从8到33 M行。所有答案的时间都是相似的,除了Chrysophylaxs的时间更快(rhug 123和Corralian/LaurentB的时间分别对于大/小 Dataframe 更慢)。

0ve6wy6x

0ve6wy6x4#

下面是另一个解决方案:

df.loc[df['col1'].iloc[::-1].ne(3).rank(method = 'first').ne(1)]

输出:

col1  col2
0     0     0
1     1    11
2     2    21
3     3    31
4     3    32
5     3    33
7     4    41
8     5    51
9     6    61
r6vfmomb

r6vfmomb5#

df.drop(index=df[df['col1'].eq(3)].index[-1:], axis=0)
col1  col2
0     0     0
1     1    11
2     2    21
3     3    31
4     3    32
5     3    33
7     4    41
8     5    51
9     6    61
qqrboqgw

qqrboqgw6#

编辑:
筛选最后一个3的索引并将其删除:

df1 = df.drop(df.index[df['col1'].eq(3)][-1])

如果可能,始终存在值3,您可以找到索引并删除它:

df1 = df.drop((df['col1'].iloc[::-1] == 3).idxmax())

在numpy里也是这样:

df1 = df.drop(np.argwhere(df['col1'].to_numpy() == 3)[-1])

计时非常相似:

#Last value of 1M is 3
np.random.seed(100)
df = pd.DataFrame({'col1': np.random.randint(100, size=1000000)})
df.loc[len(df), 'col1'] = 3
#print (df)

In [261]: %timeit df.loc[ df["col1"].ne(3) | df["col1"].duplicated(keep="last") ]
43.8 ms ± 479 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [262]: %timeit df.drop(df[df['col1'].eq(3)].index[-1])
44.4 ms ± 120 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [263]: %timeit df.drop(df[df['col1'].eq(3)].index[-1:])
44.8 ms ± 490 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [264]: %timeit df.drop((df['col1'].iloc[::-1] == 3).idxmax())
44.6 ms ± 1.62 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [265]: %timeit df.drop(np.argwhere(df['col1'].to_numpy() == 3)[-1])
43.3 ms ± 422 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [266]: %timeit df.drop(df['col1'].where(df['col1'].eq(3)).last_valid_index())
64.3 ms ± 11.3 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [267]: %timeit df.loc[df['col1'].iloc[::-1].ne(3).rank(method = 'first').ne(1)]
168 ms ± 2.59 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

相关问题