【问题标题】:Pandas DataFrame filtering of groups of rows on multiple columnsPandas DataFrame过滤多列上的行组
【发布时间】:2021-12-06 16:47:02
【问题描述】:

这是我的数据框的简化版本:

d = {'col1': ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3', 'd1', 'd2', 'd3'], 'col2': [1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1], 'col3': [-1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1]}
df = pd.DataFrame(d)
df
    col1    col2    col3
0   a1       1      -1
1   a2       1      -1
2   a3       1       1
3   b1      -1      -1
4   b2      -1      -1
5   b3      -1       1
6   c1      -1       1
7   c2       1       1
8   c3       1       1
9   d1      -1      -1
10  d2       1      -1
11  d3       1       1

我希望能够只提取那些在col3 == 1 第一次 ncol2 == 1 第一次之后的行,每个字母组。

例如,如果我们在 col2 变为 1(对于每个字母组)之后寻找 col3 变为 1 一行的时间,我们将得到

    col1    col2    col3
0   d3      1       1

因为对于组 d,col2 在 d2 时从 -1 变为 1,而 col3 在 d3 时从 -1 变为 1。而这在任何其他群体中都没有发生过。

如果我们想要 col3 变为 1 的行 两行 在 col2 变为 1 之后(对于每个字母组),我们将得到

    col1    col2    col3
0   a3      1       1

因为对于组 a,col2 在 a1 处从 1 开始,而 col3 在 a3 处从 -1 变为 1。

编辑:

这是我尴尬的做法……有人有更优雅的解决方案吗?

df['newCol'] = (
           (((df['col2'].shift(n+1).isnull() | (df['col2'].shift(n+1) == -1)) &
           (df['col2'].shift(n+1).isnull() | (df['col2'].shift(n+1) == -1))) |
           (df['col1'].shift(n+1).str[0] != df['col1'].str[0])) &
           (df['col2'].shift(n) == 1) &
           (df['col3'].shift(n) == -1) &
           (df['col2'].shift(1) == 1) &
           (df['col3'].shift(1) == -1) &
           (df['col2'] == 1) &
           (df['col3'] == 1) &
           (df['col1'].shift(n).str[0] == df['col1'].str[0])) if n > 0 \
            else \
           ((((df['col2'].shift(n+1).isnull() | (df['col2'].shift(n+1) == -1)) &
           (df['col2'].shift(n+1).isnull() | (df['col2'].shift(n+1) == -1))) |
           (df['col1'].shift(n+1).str[0] != df['col1'].str[0])) &
           (df['col2'] == 1) &
           (df['col3'] == 1))
    

【问题讨论】:

  • col1 是你的标签,你的意思是 col2beame 1 之后?
  • @QuangHoang 抱歉,是的,刚刚修好了
  • 我建议阅读一些关于如何过滤数据帧的 Pandas 文档。您将能够相对较快地回答这个问题。
  • @mrp 我知道如何进行基本过滤。然而,我发现这是一个挑战。
  • 一种可能更高效的方法是使用shift() 创建一个滞后于条件列的新列。因此,您可以在数组上使用 pandas 标准过滤器进行过滤,如果您的数据框非常大,这将更快。

标签: python pandas dataframe filter


【解决方案1】:

将我的最后评论放入答案中。使用n 创建一个滞后的新列,然后只需过滤标准方式并获取col1 的第一个值。

n = 2
df['newCol'] = df['col2'].shift(n)
df.loc[(df['col3'] == 1) & (df['newCol'] == 1), ['col1']].values[0]

你可以把它包装成一个函数,然后把所有东西都变成参数。

【讨论】:

  • ----- 编辑 nm,我试图只获取行,而忘记了 values[0] 部分......我想我需要在之后将数组转换回数据帧? ----- 关闭,但不完全。试试这个: d = {'col1': ['a1', 'a2', 'a3', 'a4', 'b1', 'b2', 'b3', 'b4', 'c1', 'c2' , 'c3', 'c4', 'd1', 'd2', 'd3', 'd4'],'col2': [1, 1, 1, 1, -1, -1, -1, -1 , -1, 1, 1, 1, 1, 1, 1, 1],'col3': [-1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1]}。那应该只是 a3,但它会返回 a3、a4、c4、d2、d3、d4。
  • 让我再搞砸它,我仍然觉得它不完全这样做>.
【解决方案2】:

试试这个:

n=2
cond = pd.concat([(df['col2'] == 1).groupby(df['col1'].str[0]).cumsum().shift(n),
                  (df['col3'] == 1).groupby(df['col1'].str[0]).cumsum()], 
                 axis=1)\
         .eq(1)\
         .all(axis=1)
df[cond]

输出:

  col1  col2  col3
2   a3     1     1

或者更简单的我认为:

cond1 = (df['col2'] == 1).groupby(df['col1'].str[0]).cumsum().shift(n) == 1
cond2 = (df['col3'] == 1).groupby(df['col1'].str[0]).cumsum() == 1
df[cond1 & cond2]

【讨论】:

  • 第一个脚本几乎可以工作,但 n=3 仍然返回 d2 它不应该返回任何东西。第二个脚本似乎根本不起作用。
  • @Raksa 当我运行 n=3 时,我得到了空的数据帧。无论如何,我认为这是一种可以对数据进行故障排除的方法。
猜你喜欢
  • 1970-01-01
  • 2021-08-27
  • 2021-09-05
  • 2020-09-01
  • 2013-09-02
  • 2012-10-21
  • 2019-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多