【问题标题】:Count items greater than a value in pandas groupby计数大于熊猫 groupby 中的值的项目
【发布时间】:2017-04-04 07:05:44
【问题描述】:

我有 Yelp 数据集,我想统计所有超过 3 星的评论。我通过这样做来计算评论数:

reviews.groupby('business_id')['stars'].count()

现在我想获取超过 3 星的评论数,所以我从here 获得灵感来尝试这个:

reviews.groupby('business_id')['stars'].agg({'greater':lambda val: (val > 3).count()})

但这只是像以前一样给了我所有星星的计数。我不确定这是否是正确的方法?我在这里做错了什么。 lambda表达式不遍历stars列的每个值吗?

编辑: 好吧,我觉得我很愚蠢。我应该使用 sum 函数而不是 count 来获取大于 3 的元素的值,如下所示:

reviews.groupby('business_id')['stars'].agg({'greater':lambda val: (val > 3).sum()})

【问题讨论】:

    标签: python python-3.x pandas


    【解决方案1】:

    为了性能,首先创建掩码,然后聚合sum

    (reviews['stars'] > 3).groupby(reviews['business_id']).sum().reset_index()
    

    【讨论】:

      【解决方案2】:

      由于我还想重命名列并在同一列上运行多个函数,所以我想出了以下解决方案:

      # Counting both over and under
      reviews.groupby('business_id')\
             .agg(over=pandas.NamedAgg(column='stars', aggfunc=lambda x: (x > 3).sum()), 
                  under=pandas.NamedAgg(column='stars', aggfunc=lambda x: (x < 3).sum()))\
             .reset_index()
      

      pandas.NamedAgg 允许您创建多个新列,因为新版本的 pandas 中删除了该功能。

      【讨论】:

      • 现在提供短格式:reviews.groupby('business_id').agg(over=('stars', lambda x: (x &gt; 3).sum()), under=('stars', lambda x: (x &lt; 3).sum())).reset_index()
      【解决方案3】:

      正确查询

      Python

      # Pass a df and apply the lambda function to column stars
      reviews.groupby('business_id').apply(lambda df: sum(df.stars > 3))
      

      代码说明

      lambda df: sum(df.stars > 3)
      

      这个 lambda 函数需要一个 pandas DataFrame 实例,然后过滤 if df.stars &gt; 3。如果是这样,则 lambda 函数将获得 True 否则为 False。最后,sumTrue 记录。 由于我在执行此 lambda 函数之前应用了groupby,因此它将为每个组提供sumif df.stars &gt; 3


      等效的 SQL 语句

      SELECT
          business_id,
          SUM(IF(starts > 3, 1, 0)) AS starts_>3
      FROM reviews
      GROUP BY business_id;
      

      SELECT
          business_id,
          COUNT(IF(starts > 3, 1, NULL)) AS starts_>3
      FROM reviews
      GROUP BY business_id;
      

      查询错误

      Python

      reviews[reviews.stars > 3].groupby('business_id').size()
      

      reviews[reviews.stars > 3].groupby('business_id')['stars'].count()
      

      等效的 SQL 语句

      SELECT
          business_id,
          SUM(IF(starts > 3, 1, 0)) AS starts_>3
      WHERE starts > 3
      FROM reviews
      GROUP BY business_id;
      

      SELECT
          business_id,
          COUNT(IF(starts > 3, 1, NULL)) AS starts_>3
      FROM reviews
      WHERE starts > 3
      GROUP BY business_id;
      

      为什么错了?

      如您所见,错误的Python查询使用reviews[reviews.stars &gt; 3]过滤groupby('business_id)之前大于3的星数,相当于在SQL中在GROUP BY business_id之前应用WHERE stars &gt; 3

      因此,假设您有一个 business_id,其中只有记录 stars &lt;= 3。错误的查询将忽略这个business_id。而且你不会数他们。


      有什么改善吗?

      是的。您可以改进 python 查询以重命名查询结果。 Pandas 不如 PySpark 方便,但我们仍然可以命名列名。

      # Pass a df and apply the lambda function to column stars
      lambda_func = lambda df: pd.Series({'stars_>3': df.stars > 3})
      reviews.groupby('business_id').apply(lambda_func)
      

      评估

      生成样本数据集

      您可以使用以下代码进行评估:

      import pandas as pd
      import random
      
      # define business_ids
      business_ids = range(1, 4)
      
      # define stars
      stars = range(1, 6)
      
      # Generate a sample table reviews
      reviews = pd.DataFrame(columns = ['review_id', 'business_id', 'stars'])
      for business_id in business_ids:
          for i in range(random.randrange(1, 5)): # Assume each business_id has 1~4 reviews
              review = [len(reviews)+1, business_id, random.choice(stars)]
              reviews.loc[len(reviews)] = review
      reviews
      

      我的示例数据集:

      review_id business_id stars
      0 1 1 4
      1 2 1 5
      2 3 1 4
      3 4 1 1
      4 5 2 3
      5 6 2 5
      6 7 2 2
      7 8 2 3
      8 9 3 3
      9 10 3 1
      10 11 3 3

      正确的 Python 查询

      """
      business_id, stars_>3
      1, 3
      2, 1
      3, 0
      """
      # Pass a df and apply the lambda function to column stars
      lambda_func = lambda df: pd.Series({'stars_>3': sum(df.stars > 3)})
      reviews.groupby('business_id').apply(lambda_func)
      
      stars_>3
      business_id
      1 3
      2 1
      3 0

      错误的 Python 查询

      reviews[reviews.stars > 3].groupby('business_id')['stars'].count()
      

      输出:

      business_id
      1    3
      2    1
      

      【讨论】:

      • 请添加一些解释您的代码如何工作以及为什么您的答案可能比其他人更好。谢谢!
      【解决方案4】:

      我非常喜欢使用method chaining with Pandas,因为我发现它更易于阅读。我还没有尝试过,但我认为这也应该有效

      reviews.query("stars > 3").groupby("business_id").size()
      

      【讨论】:

        【解决方案5】:

        有点晚了,但我的解决办法是:

        reviews.groupby('business_id').stars.apply(lambda x: len(x[x>3]) )
        

        我在寻找“在给定的 GroupBy 中高于 X 的值的分数是多少”时遇到了这个线程。 如果有人感兴趣,这里是解决方案:

        reviews.groupby('business_id').stars.apply(lambda x: len(x[x>3])/len(x) )
        

        【讨论】:

          【解决方案6】:

          你可以尝试做:

          reviews[reviews['stars'] > 3].groupby('business_id')['stars'].count()
          

          【讨论】:

          • 酷!这样可行。非常感谢。我对熊猫有点陌生,所以你介意告诉我一些关于你的分组方法与我对数据分组的方式相比的工作原理吗?哪一个更高效?
          • 我认为在过滤数据集时使用“掩码”语法比遍历所有数据要好。
          • webpages.uidaho.edu/~stevel/504/Pandas%20DataFrame%20Notes.pdf 这是一个非常好的备忘单,你可以在处理 pandas 时使用
          • 谢谢,非常感谢您的帮助!
          • 但是,这将无法告诉您哪个 business_id 的计数为零
          猜你喜欢
          • 2020-09-21
          • 1970-01-01
          • 2019-10-13
          • 1970-01-01
          • 1970-01-01
          • 2020-01-16
          • 1970-01-01
          • 2018-04-29
          • 1970-01-01
          相关资源
          最近更新 更多