我有一个场景,用户想要将几个过滤器应用到Pandas DataFrame或Series对象。本质上,我希望有效地将用户在运行时指定的一堆过滤(比较操作)链接在一起。
过滤器应为添加剂(即,应用的每个过滤器应缩小结果范围)。
我目前正在使用reindex()
,但这每次都会创建一个新对象并复制基础数据(如果我正确理解留档)。因此,在过滤大型系列或数据帧时,这可能非常低效。
我认为使用apply()
、map()
或类似的方法可能会更好。我对熊猫还不太熟悉,所以我还是试着去了解一切。
我想使用以下形式的字典,并将每个操作应用于给定的Series对象,并返回一个筛选的Series对象。
relops = {'>=': [1], '<=': [1]}
我将从一个我目前拥有的示例开始,只过滤一个序列对象。以下是我当前使用的函数:
def apply_relops(series, relops):
"""
Pass dictionary of relational operators to perform on given series object
"""
for op, vals in relops.iteritems():
op_func = ops[op]
for val in vals:
filtered = op_func(series, val)
series = series.reindex(series[filtered])
return series
用户提供一个字典,其中包含要执行的操作:
>>> df = pandas.DataFrame({'col1': [0, 1, 2], 'col2': [10, 11, 12]})
>>> print df
>>> print df
col1 col2
0 0 10
1 1 11
2 2 12
>>> from operator import le, ge
>>> ops ={'>=': ge, '<=': le}
>>> apply_relops(df['col1'], {'>=': [1]})
col1
1 1
2 2
Name: col1
>>> apply_relops(df['col1'], relops = {'>=': [1], '<=': [1]})
col1
1 1
Name: col1
同样,我上述方法的“问题”是,我认为中间步骤可能存在大量不必要的数据复制。
此外,我还想对此进行扩展,以便传入的字典可以包括要运算符打开的列,并基于输入字典过滤整个数据帧。然而,我假设任何适用于该系列的东西都可以轻松地扩展为数据帧。
最简单的解决方案:
使用:
filtered_df = df[(df['col1'] >= 1) & (df['col1'] <= 5)]
另一个例子是,要过滤数据帧中属于2018年2月的值,请使用以下代码
filtered_df = df[(df['year'] == 2018) & (df['month'] == 2)]
连锁条件产生长线,这是由Pep8劝阻。使用。查询方法强制使用字符串,这是强大的,但不是Pythonic,也不是非常动态的。
一旦每个过滤器都到位,一种方法是
import numpy as np
import functools
def conjunction(*conditions):
return functools.reduce(np.logical_and, conditions)
c_1 = data.col1 == True
c_2 = data.col2 < 64
c_3 = data.col3 != 4
data_filtered = data[conjunction(c1,c2,c3)]
np.logical在上运行且速度快,但不接受两个以上的参数,这由functools.reduce处理。
请注意,这仍然有一些冗余: a)快捷方式不会在全局级别上发生b)每个单独的条件都在整个初始数据上运行。尽管如此,我希望这对于许多应用程序来说足够高效,并且非常可读。
您还可以使用np.logical\u或
进行析取(其中只有一个条件需要为真):
import numpy as np
import functools
def disjunction(*conditions):
return functools.reduce(np.logical_or, conditions)
c_1 = data.col1 == True
c_2 = data.col2 < 64
c_3 = data.col3 != 4
data_filtered = data[disjunction(c_1,c_2,c_3)]
熊猫(和numpy)允许布尔索引,这将更加有效:
In [11]: df.loc[df['col1'] >= 1, 'col1']
Out[11]:
1 1
2 2
Name: col1
In [12]: df[df['col1'] >= 1]
Out[12]:
col1 col2
1 1 11
2 2 12
In [13]: df[(df['col1'] >= 1) & (df['col1'] <=1 )]
Out[13]:
col1 col2
1 1 11
如果您想为此编写帮助函数,请考虑以下内容:
In [14]: def b(x, col, op, n):
return op(x[col],n)
In [15]: def f(x, *b):
return x[(np.logical_and(*b))]
In [16]: b1 = b(df, 'col1', ge, 1)
In [17]: b2 = b(df, 'col1', le, 1)
In [18]: f(df, b1, b2)
Out[18]:
col1 col2
1 1 11
更新:pandas 0.13为此类用例提供了一种查询方法,假设列名是有效的标识符,下面的工作(并且对于大帧来说可能更有效,因为它在幕后使用numexpr):
In [21]: df.query('col1 <= 1 & 1 <= col1')
Out[21]:
col1 col2
1 1 11
若要用单个列过滤数据文件(DF),如果我们考虑有男性和女性的数据,我们可以: 问题1——但如果数据跨越多年,而我只想看到2014年的男性会怎样? 在其他语言中,我可能会这样做: (除非我想这样做并在新的dataframe对象中获取原始dataframe的子集) 问题2。我如何在一个循环中实现这一点,并为每个独特的年份和性别集(即:2013年男性、2013年女性、2014年男性和2014年女性)创建
我正在尝试筛选将< code>None作为行值的PySpark数据帧: 我可以使用字符串值正确过滤: 但这失败了: 但是每一类都有明确的价值。这是怎么回事?
我有两个数据帧。我需要用第二列中的平均值更新第一列中的一列,并按索引分组。这里是示例df1(col1是索引) df2(col1是索引) 我需要df2的col2(a=2,d=3)的平均值,并且只更新col3=X的行的df1 我试过这个 只有在我不使用loc的情况下,它才有效。 我试图得到的结果是df1(col1是索引)
这一组数据在进行groupby前已经完成筛选,但进行groupby聚合后的结果显示是利用未筛选的数据进行的聚合,就像下面的结果,在groupby前已经完成点击量非0过滤,但最后仍存在含0的资源,询问chatGPT给的方案是可能用索引前的数据进行的聚合,重置索引后仍无法解决,请教大牛是否遇到过类似的问题,虽然可以在聚合后重新进行filter过滤,但这个问题搞得很焦灼 代码源文本
我有一个关于熊猫以及正确索引和替换值的问题。 我有两个数据帧,df1和df2,具有相同的列(Col1、Col2、Col3和Col4)。 在df1中,我想用另一个值(比如100)替换与df2中其他列(Col1、Col2和Col3)的值匹配的行中Col4中的值。 生成的df1看起来像这样: 我试过这样的方法: 但是我得到了错误,我不确定这是否达到了我想要的。
筛选数据 你可以通过 3 种方式筛选数据: 点击字段框中的向下箭头,然后选择“筛选”。 使用筛选窗格。 右击图表上的系列或数据点。 【提示】如果要清除筛选,则需要使用筛选窗格。 排序数据 你可以通过 2 种方式排序数据: 点击字段框中的向下箭头,然后选择“排序”。 使用排序窗格。