是否有pandas Series(pandas.Series.query())的查询方法或类似方法?

时间:2016-10-21 08:11:21

标签: python pandas dataframe series method-chaining

在加载或绘图时,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

请帮助我摆脱困境!感谢

3 个答案:

答案 0 :(得分:7)

IIUC您可以添加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

答案 1 :(得分:3)

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

65, A
66, B
67, C

65, A
66, B
67, C

此处,df["Points"] = df["Points"].to_frame().query('Points > 100')["Points"] 转换为DataFrame,而尾随.to_frame()转换为系列。

无论Pandas对象是否包含1列或更多列,都可以一致地使用方法["Points"]

答案 2 :(得分:2)

您可以使用pipe代替查询:

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