【问题标题】:Choose a series of rows between two other rows that contain specific values or strings在包含特定值或字符串的其他两行之间选择一系列行
【发布时间】:2021-02-21 22:06:32
【问题描述】:

编辑:
如果 Keyword1 和 Keyword2 的出现次数不匹配,则提供的解决方案不起作用。我更新了下面的数据框和代码以反映类似的不匹配。

原帖:
我有一个字符串数据框,我正在尝试选择两个特定字符串值 [Keyword1 和 Keyword2] 之间的所有行。

我正在使用下面的代码:

import pandas as pd 
import numpy as np

df=pd.DataFrame(['A', 'B', 'C1', 'D', 'A', 'B', 'C2','C3', 'D','C4', 'B', 'C5'])
df.columns = ['Col1']

Keyword1= 'B'
Keyword2= 'D'

#Filter and delete file mode deliveries
a=df.index[df['Col1'] == Keyword1].tolist()
b=df.index[df['Col1'] == Keyword2].tolist() 
b=np.add(b, 1).tolist() 
 

index=[]
for i in range(len(b)):
    index_temp=np.arange(a[i],b[i]).tolist()
    index=index+index_temp

df_keep= df[df.index.isin(index)]   
df_del= df[~df.index.isin(index)]

虽然这可以工作,但我想知道是否有更有效的方法来执行相同的任务。

【问题讨论】:

  • 不确定为什么第一行在df_del 中,因为它不在两个关键字之间。请看我的回答。
  • 在您的新输出中,对我来说没有意义的值是:1) 第一项——它不在DB 之间。它是第一项,因此它不能位于两项之间。 2) 为什么输出倒数第二项B?我们在DB 之间输出,那么为什么会输出这个B? 3)同样,为什么最后一个项目C5输出了而其他没有?它是最后一项,而不是在两项之间。
  • 将“B”视为起始字符串,将“D”视为结束字符串。属于此类别的项目是:B、C1、D、B、C2、C3、D。这些项目进入 df_keep,其余项目进入 df_del。

标签: python pandas string dataframe


【解决方案1】:

这是一种方法:

df[((df.eq(Keyword2)*-1).shift().bfill() + df.eq(Keyword1)).cumsum().astype(bool)['Col1']]

输出:

   Col1
1     B
2    C1
3     D
5     B
6    C2
7    C3
8     D
10    B
11   C5
12    D

使用 eq 将 1 分配给关键字 1,将 -1 分配给关键字 2,然后使用 cumsum 查找值等于 1 的所有位置,使用 astype 将其更改为 True,然后对数据帧和 dropna 进行布尔索引。

详情:

m1 = (df.eq(Keyword2)*-1).shift().bfill() #find the Keyword2
m1

输出:

    Col1
0    0.0
1    0.0
2    0.0
3    0.0
4   -1.0
5    0.0
6    0.0
7    0.0
8    0.0
9   -1.0
10   0.0
11   0.0
12   0.0

接下来,

m2 =  df.eq(Keyword1) #find the Keyword1
print(m2)

输出:

     Col1
0   False
1    True
2   False
3   False
4   False
5    True
6   False
7   False
8   False
9   False
10   True
11  False
12  False

还有,

(m1 + m2).cumsum()

    Col1
0    0.0
1    1.0
2    1.0
3    1.0
4    0.0
5    1.0
6    1.0
7    1.0
8    1.0
9    0.0
10   1.0
11   1.0
12   1.0

【讨论】:

  • 只要 Keyword1 和 Keyword2 的出现次数相同,就可以使用。如果不匹配,则不起作用。
【解决方案2】:

再试一次:

ix1= np.where(df.Col1.eq('B'))[0]
ix2= np.where(df.Col1.eq('D'))[0]
df_keep = pd.concat([df.Col1.iloc[start:end+1] for start, end in zip(ix1,ix2)])

打印:

1      B
2     C1
3      D
5      B
6     C2
7     C3
8      D
10     B
11    C5
12     D

【讨论】:

    【解决方案3】:

    这应该比循环更有效。您可以创建一系列条件c1c2,它们是基于cumsum 逻辑和idxmin 的布尔系列,它们基本上告诉您值是否介于DB 之间。使用 cumsum 可以帮助您识别值的变化 BD 这可以帮助您找到介于两者之间的值:

    df['s'] = ((df['Col1'] == 'D') | (df['Col1'] == 'B')).cumsum()
    c1 = (df.index != df.groupby('s')['s'].transform('idxmin'))
    c2 = ((df['Col1'] == 'B').cumsum() == (df['Col1'] == 'D').cumsum())
    df_del = df[c1 & c2].drop('s', axis=1)
    df_del
    Out[1]: 
      Col1
    4    A
    9   C4
    
    df_keep = df[~(c1 & c2)].drop('s', axis=1)
    df_keep
    Out[2]: 
       Col1
    0     A
    1     B
    2    C1
    3     D
    5     B
    6    C2
    7    C3
    8     D
    10    B
    11   C5
    12    D
    

    【讨论】:

    • 嗨,大卫,感谢您的解决方案。但正如您正确指出的那样,第一个“A”被遗漏了。
    猜你喜欢
    • 2021-12-01
    • 2015-10-17
    • 1970-01-01
    • 1970-01-01
    • 2018-08-15
    • 2021-09-15
    • 2015-12-22
    • 1970-01-01
    • 2021-09-17
    相关资源
    最近更新 更多