Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 忽略数据帧上多个筛选器中的无效筛选器 问题陈述:_Python_Pandas_Dataframe - Fatal编程技术网

Python 忽略数据帧上多个筛选器中的无效筛选器 问题陈述:

Python 忽略数据帧上多个筛选器中的无效筛选器 问题陈述:,python,pandas,dataframe,Python,Pandas,Dataframe,我有一个数据帧,必须用多个条件进行过滤 每个条件都是可选的,这意味着如果用户为某个条件输入了无效值,则可以完全跳过该条件,默认为原始数据帧(没有该特定条件) 虽然我可以在多个if条件下很容易地实现这一点,以顺序方式修改数据帧,但我正在寻找更优雅和可伸缩的东西(增加输入参数),最好使用内置功能 可复制示例 虚拟数据帧- df = pd.DataFrame({'One':['a','a','a','b'], 'Two':['x','y','y','y'],

我有一个数据帧,必须用多个条件进行过滤

每个条件都是可选的,这意味着如果用户为某个条件输入了无效值,则可以完全跳过该条件,默认为原始数据帧(没有该特定条件)

虽然我可以在多个if条件下很容易地实现这一点,以顺序方式修改数据帧,但我正在寻找更优雅和可伸缩的东西(增加输入参数),最好使用内置功能

可复制示例 虚拟数据帧-

df = pd.DataFrame({'One':['a','a','a','b'], 
                   'Two':['x','y','y','y'], 
                   'Three':['l','m','m','l']})

print(df)
假设无效值是不属于相应列的值。因此,对于列“One”,除了“a”和“b”之外,所有其他值都无效。如果用户输入的是'a',那么我应该能够过滤数据帧
df[df['One']='a']
,但是,如果用户输入任何无效值,则不应应用此类过滤器,并返回原始数据帧
df

我的尝试(使用多个参数):

使用所有有效输入-

inp = ['a','y','m']             #<- all filters valid so df is filtered before returning
print(valid_filtering(df, inp))
inp = ['a','NA','NA']           #<- only first filter is valid, so other 2 filters are ignored
print(valid_filtering(df, inp))
几乎没有无效的输入-

inp = ['a','y','m']             #<- all filters valid so df is filtered before returning
print(valid_filtering(df, inp))
inp = ['a','NA','NA']           #<- only first filter is valid, so other 2 filters are ignored
print(valid_filtering(df, inp))

p.S.另外一个问题-有没有办法让数据帧索引表现为-

df[df['One']=='valid'] -> returns filtered df

df[df['One']=='invalid'] -> returns original df
因为这将帮助我重写过滤-

df[(df['One']=='valid') & (df['Two']=='invalid') & (df['Three']=='valid')] -> Filtered by col One and Three

编辑:解决方案- 受@correlian和@Ben.T提供的代码和逻辑启发的更新解决方案

df.loc[(df.eq(inp)|~df.eq(inp).any(0)).all(1)]

下面是一种根据每列中inp的每个值创建布尔数据帧的方法。然后沿行使用
any
以获得至少有一个True的列,并在选择至少有一个True的列后沿列使用
all

def valid_filtering(df, inp):
    # check where inp values are same than in df
    m = (df==pd.DataFrame(data=[inp] , index=df.index, columns=df.columns))
    # select the columns with at least one True
    cols = m.columns[m.any()]
    # select the rows that all True amongst wanted columns
    rows = m[cols].all(axis=1)
    # return df with selected rows
    return df.loc[rows]
请注意,如果您没有与原始df中的列数相同的筛选器,那么您可以使用字典,它也可以工作,如下面的示例所示,列3将被忽略,因为all
False

d = {'One': 'a', 'Two': 'y'}
m = (df==pd.DataFrame(d, index=df.index).reindex(columns=df.columns))

关键是如果列返回all False(
~b.any
,无效筛选器),则返回True以接受此列的所有值:

mask=df.eq(inp).apply(lambda b:np.where(~b.any(),True,b))
out=df.loc[屏蔽所有(axis=“columns”)]
案例1
inp=['a','y','m']
(包含所有有效输入)

>>输出
一二三
1 a y m
上午2点
案例2
inp=['a','NA','NA']
(很少有无效输入)

>>输出
一二三
0 a x l
1 a y m
上午2点
案例3
inp=['NA','NA','NA']
(无无效输入)

>>输出
一二三
0 a x l
1 a y m
上午2点
3 b y l
案例4
inp=['b','x','m']
(包含所有有效输入,但不包含结果)

当然,您可以增加输入参数:

def valid_filtering(df, inp):
    if inp[0] in df['One'].values:
        df = df[df['One']==inp[0]]

    if inp[1] in df['Two'].values:
        df = df[df['Two']==inp[1]]

    if inp[2] in df['Three'].values:
        df = df[df['Three']==inp[2]]
        
    return df
df[“四”]=['i','j','k','k']
inp=['a','NA','m','k']

列表理解的另一种方式:

def valid_filtering(df, inp):
    series = [df[column] == inp[i]
        for i, column in enumerate(df.columns) if len(df[df[column] == inp[i]].values) > 0]
    for s in series: df = df[s]
    return df
打印输出(有效过滤(df、['a'、'NA'、'NA'])


相关:

在第二种情况下,
是否为“有效”
是否为“无效”
实际上是那些字符串,还是仅仅是一个有效或无效的值?但是似乎你的问题可以通过把dict作为参数来解决,比如
d={'One':'a'}
或者
d={'One':'a','Two':'y','Three':'m'}
,这样你就可以更灵活地指定你需要过滤的一些或所有列,在dict上迭代,我指的是有效值和无效值,而不是基本相同的逻辑。基于字典的筛选器肯定是我可以使用的,使用
df.loc[df[filter\u v.keys()].isin(filter\u v.values()).all(axis=1),:]
但是,问题是,在创建过滤器字典之前,我必须收集有效值和无效值的列表。伟大的解决方案,我从你的解决方案和Ben.T的解决方案中得到灵感,提出了一个不使用apply方法的逻辑。我更新的答案中的详细信息。太糟糕了,我只能将一个答案标记为正确。非常感谢,我将您的解决方案与Corrarien的解决方案结合起来,得出了我最终使用的代码。更新我的答案,谢谢@AkshaySehgal非常棒的解决方案,我有点惊讶在完整数据帧df.eq(inp)和系列~df.eq(inp)之间执行or操作。任何(0)都是这样工作的,但我稍后会尝试记住这一点:)
>>> out
Empty DataFrame
Columns: [One, Two, Three]
Index: []
>>> out
  One Two Three Four
2   a   y     m    k
def valid_filtering(df, inp):
    series = [df[column] == inp[i]
        for i, column in enumerate(df.columns) if len(df[df[column] == inp[i]].values) > 0]
    for s in series: df = df[s]
    return df
  One Two Three
0   a   x     l
1   a   y     m
2   a   y     m