【问题标题】:Is there a query method or similar for pandas Series (pandas.Series.query())?熊猫系列(pandas.Series.query())是否有查询方法或类似方法?
【发布时间】:2016-10-21 08:11:20
【问题描述】:

pandas.DataFrame.query() 方法对于加载或绘图时(前/后)过滤数据非常有用。它对于方法链接特别方便。

我发现自己经常想将相同的逻辑应用于pandas.Series,例如在完成诸如 df.value_counts 之类的方法之后,该方法返回 pandas.Series。

示例

假设有一个包含Player, Game, Points 列的巨大表格,我想绘制一个超过 14 乘以 3 点的玩家的直方图​​。我首先必须对每个玩家 (groupby -> agg) 的积分求和,这将返回一系列约 1000 名玩家及其总分。应用.query 逻辑,它看起来像这样:

df = pd.DataFrame({
    'Points': [random.choice([1,3]) for x in range(100)], 
    'Player': [random.choice(["A","B","C"]) for x in range(100)]})

(df
     .query("Points == 3")
     .Player.values_count()
     .query("> 14")
     .hist())

我发现的唯一解决方案迫使我进行不必要的分配并破坏方法链接:

(points_series = df
     .query("Points == 3")
     .groupby("Player").size()
points_series[points_series > 100].hist()

方法链和查询方法有助于保持代码清晰,同时子集过滤很快就会变得混乱。

# just to make my point :)
series_bestplayers_under_100[series_prefiltered_under_100 > 0].shape

请帮助我摆脱困境!谢谢

【问题讨论】:

  • 我不确定 SO 是否是解决这个问题的最佳地点,因为这是该库开发人员的问题,最好在 githubIMO 上发帖
  • 将问题标题更改为更像 SO-Like

标签: python pandas dataframe series method-chaining


【解决方案1】:

如果我理解正确你可以添加query("Points > 100"):

df = pd.DataFrame({'Points':[50,20,38,90,0, np.Inf],
                   'Player':['a','a','a','s','s','s']})

print (df)
  Player     Points
0      a  50.000000
1      a  20.000000
2      a  38.000000
3      s  90.000000
4      s   0.000000
5      s        inf

points_series = df.query("Points < inf").groupby("Player").agg({"Points": "sum"})['Points']
print (points_series)     
a = points_series[points_series > 100]
print (a)     
Player
a    108.0
Name: Points, dtype: float64


points_series = df.query("Points < inf")
                  .groupby("Player")
                  .agg({"Points": "sum"})
                  .query("Points > 100")

print (points_series)     
        Points
Player        
a        108.0

另一种解决方案是Selection By Callable:

points_series = df.query("Points < inf")
                  .groupby("Player")
                  .agg({"Points": "sum"})['Points']
                  .loc[lambda x: x > 100]

print (points_series)     
Player
a    108.0
Name: Points, dtype: float64

已编辑问题的编辑答案:

np.random.seed(1234)
df = pd.DataFrame({
    'Points': [np.random.choice([1,3]) for x in range(100)], 
    'Player': [np.random.choice(["A","B","C"]) for x in range(100)]})

print (df.query("Points == 3").Player.value_counts().loc[lambda x: x > 15])
C    19
B    16
Name: Player, dtype: int64

print (df.query("Points == 3").groupby("Player").size().loc[lambda x: x > 15])
Player
B    16
C    19
dtype: int64

【讨论】:

  • 哦,哇,我的例子很糟糕! groupby 实际上返回一个DataFrame。但是例如pd.DataFrame.value_counts() 返回一个系列,您的解决方案会派上用场!通过 Callable 选择,我不知道 - 谢谢
  • 好的,我为你的新问题添加答案 - callable 很少使用,因为它是新功能。
  • 好的,我看到它是最近才添加的。很好的补充!
【解决方案2】:

为什么不从 Series 转换为 DataFrame,进行查询,然后再转换回来。

df["Points"] = df["Points"].to_frame().query('Points > 100')["Points"]

这里,.to_frame() 转换为 DataFrame,而尾随的 ["Points"] 转换为 Series。

无论 Pandas 对象是否有 1 列或更多列,都可以一致地使用方法 .query()。

【讨论】:

    【解决方案3】:

    你可以使用pipe代替查询:

    s.pipe(lambda x: x[x>0]).pipe(lambda x: x[x<10])
    

    【讨论】:

    • 这只给你布尔掩码。它不查询/过滤系列。
    • @MichelePiccolini,你确定吗?它确实为我过滤了这个系列。
    猜你喜欢
    • 1970-01-01
    • 2019-01-14
    • 2019-07-04
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    • 2018-02-25
    • 2021-09-18
    • 2021-09-12
    相关资源
    最近更新 更多