【问题标题】:How to filter rows from dataframe depending on contents of other rows?如何根据其他行的内容从数据框中过滤行?
【发布时间】:2022-07-01 05:55:17
【问题描述】:

假设我有一个数据框定义为

pd.DataFrame({'col1': ['foo', '', '', 'foo', 'quux', 'baz', 'baz', 'baz'],
              'col2': ['', 'gb', '', 'de', 'gb', '', 'es', 'es'],
              'col3': [123, float("NaN"), 456, 723, 456, 123, 123, 721],
              'col4': ['', '', 'val1', 'val2', 'val3', '', 'val4', 'val5'],
              'value': [1, 1, .4, .5, .3, 1, .5, .4]})

看起来像

index col1 col2 col3 col4 value
0 foo 123.0 1.0
1 gb NaN 1.0
2 456.0 val1 0.4
3 foo de 723.0 val2 0.5
4 quux gb 456.0 val3 0.3
5 baz 123 1
6 baz es 123 val4 .5
7 baz es 721 val5 0.4

我想过滤此表并删除值等于 1.0 的所有行,以及填充列中与 value==1.0 行具有相同值的所有行。因此,在上表中,我们将删除第 0、1 和 5 行,因为 value==1.0,同时删除第 3 行,因为 col1=='foo',第 4 行,因为 col2=='gb',第 6 行,因为col1='baz' 和 col3=123。应保留第 2 行和第 7 行。

index col1 col2 col3 col4 value
2 456.0 val1 0.4
3 foo de 723.0 val2 0.5
7 baz es 721 val5 0.4

最好的方法是什么?我可以找到 value==1.0 的所有行,然后遍历它们并从表中过滤掉在设置列中具有相同值的所有行,但是遍历数据框行并不理想。我也想过进行合并,但我也不确定如何告诉合并忽略没有设置值的列。

【问题讨论】:

  • 如果“foo”出现在任何列中,您是否要过滤行?还是只是'col1','col2'?
  • 如果 'foo' 出现在 'col1' 中,如果 'gb' 出现在 'col2' 中。
  • 只有两个特定的字符串 'foo' 、 'gb' 或包含 1.0 的行中的任何字符串?
  • 任何包含 1.0 的行中的字符串。以及列的任意组合。因此,如果还有一行 col1 = 'something' 和 col2 = 'else' 和 value = 1.0,我想过滤 col1 = 'something' AND col2 = 'else' 的任何行,无论 col3 中的值如何和 col4。
  • 为什么虽然 col1='baz' 没有删除第 7 行?

标签: python pandas dataframe


【解决方案1】:

让我们做

cond = df.loc[df.value==1,]
filter = df[~(df.col1.isin(cond.col1[cond.col1!=''])|df.col2.isin(cond.col2[cond.col2!='']))]
filter
Out[443]: 
  col1 col2   col3  col4  value
2            456.0  val1    0.4

【讨论】:

  • 感谢您的回复!我在我认为之前没有充分说明的问题中添加了更多信息。
【解决方案2】:

我建议对每列进行处理。

# First get rows where value is 1
temp = df.query('value == 1')

# Then, collect all unique values from the columns of interest.
vals1, vals2 = temp.col1[temp.col1.ne('')].unique(), temp.col2[temp.col2.ne('')].unique()

# Finally, filter.
df.loc[~(np.isin(df.col1, vals1) | np.isin(df.col2, vals2))]

【讨论】:

  • 我认为这不起作用,因为任何列或列组合都可以用于过滤。重要的是一行中的值是否== 1。如果是,那么该行列中的所有设置值都是过滤的指标。我在问题中添加了一些关于此的澄清信息。
  • @Catherine 我提出的逻辑适用于 2 列,但很容易扩展到 N 列。您是否考虑过在列上创建一个 for 循环并保持逻辑?我相信这应该可行:)
【解决方案3】:

我通常使用numpy 进行二进制切片,因为这是直截了当并且(对我而言)最易读的:

import pandas as pd
import numpy as np

df = pd.DataFrame({'col1': ['foo', '', '', 'foo', 'quux'],
                'col2': ['', 'gb', '', 'de', 'gb'],
                'col3': [123, float("NaN"), 456, 723, 456],
                'col4': ['', '', 'val1', 'val2', 'val3'],
                'value': [1, 1, .4, .5, .3]})

target = pd.Series({'value': 1.0, 'col1': 'foo', 'col2': 'gb'})

# determine which rows meet the target specifications
lg = np.all(df[target.index] == target, axis=1)

# using slicing
df = df[~lg]
# using drop
df.drop(lg[lg].index)

这样做的好处是您可以灵活地处理如何处理逻辑向量 lg 或有趣的索引 lg[lg].index =)

【讨论】:

    【解决方案4】:

    你可以这样做:

    s = set(filter(lambda x:len(str(x)) > 0, 
               np.ravel(df.loc[df['value'].eq(1.0)].fillna('')[['col1', 'col2']].values)))
    df = df[~(df['col1'].isin(s) | df['col2'].isin(s))]
    

    【讨论】:

      【解决方案5】:

      这应该可以完成工作:

      eq1 = df[df['value'].eq(1)].replace('', float("NaN"))
      
      df[~df.apply(lambda x: (eq1 == x).any(axis=None), axis=1)]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-06-26
        • 1970-01-01
        • 2021-09-04
        • 1970-01-01
        • 1970-01-01
        • 2019-12-09
        • 2019-10-01
        • 2020-03-16
        相关资源
        最近更新 更多