【问题标题】:Filter Pandas Series using both index and value使用索引和值过滤 Pandas 系列
【发布时间】:2018-03-23 21:12:41
【问题描述】:

是否有一种干净的方法来使用将索引和值作为输入的自定义函数来过滤 Pandas 系列?

这是实现我想做的一段代码:

series = pd.Series({"id5":88, "id3":40})
def custom(k,v):
    if k=="id5":
        return v>20
    else:
        return v>50

filtered_indexes = []
filtered_values = []
for k,v in series.iteritems():
    if custom(k,v):
        filtered_indexes.append(k)
        filtered_values.append(v)
filtered_series = pd.Series(data=filtered_values, index=filtered_indexes)

我的问题是:使用类似的语法可以更清洁和/或更有效地实现同样的目标

series.filter(lambda x: custom(x.index, x.value))

【问题讨论】:

  • 您可以添加数据样本吗?

标签: python python-3.x pandas


【解决方案1】:

Series.applyhave no accesses 索引存在问题,DataFrame.filter 未针对 Series 实现。

可以,但需要创建DataFrame:

s = series[series.to_frame().apply(lambda x: custom(x.name, x), axis=1).squeeze()]
print (s)
id5    88
dtype: int64

或将groupbyfiltration 一起使用:

s = series.groupby(level=0).filter(lambda x: custom(x.name, x)[0])
print (s)
id5    88
dtype: int64

【讨论】:

    【解决方案2】:

    您可以将您的逻辑矢量化如下。这避免了低效的lambda 循环,还可以使您的代码更简洁。

    res = series[((series.index == 'id5') & (series > 20)) |
                 ((series.index != 'id5') & (series > 50))]
    

    结果:

    id5    88
    dtype: int64
    

    为了可读性,您可能希望将布尔标准分开:

    c1 = ((series.index == 'id5') & (series > 20))
    c2 = ((series.index != 'id5') & (series > 50))
    
    res = series[c1 | c2]
    

    【讨论】:

    • 谢谢,但这缺少自定义功能,我提供的示例只是一个“玩具示例”。实际功能比较复杂,不能这样表达。
    • 所以链接c1 = f(series.index, series) f 是您的自定义函数?只要确保f 返回一个数组。大体相同,此方案适用于任何功能。
    • 我不确定你的意思。特别是要“确保f 返回一个数组”。这听起来像f 只会包含我一开始就试图摆脱的所有丑陋代码。我是不是误会了什么?
    • 是的。让每个函数执行不同的操作是一种很好的做法。你还没有解释f(index, series) 涉及什么,所以我不能进一步评论。但如果是数值计算,您很可能可以通过 numpy / numba / 其他工具进行优化。当然,您始终可以采用@jezrael 的方法并将您的系列转换为数据框..
    猜你喜欢
    • 2022-06-20
    • 1970-01-01
    • 2014-04-29
    • 1970-01-01
    • 1970-01-01
    • 2016-09-06
    • 1970-01-01
    • 2019-02-24
    • 1970-01-01
    相关资源
    最近更新 更多