【问题标题】:pandas - get most recent value of a particular column indexed by another column (get maximum value of a particular column indexed by another column)pandas - 获取由另一列索引的特定列的最新值(获取由另一列索引的特定列的最大值)
【发布时间】:2012-04-08 16:57:53
【问题描述】:

我有以下数据框:

   obj_id   data_date   value
0  4        2011-11-01  59500    
1  2        2011-10-01  35200 
2  4        2010-07-31  24860   
3  1        2009-07-28  15860
4  2        2008-10-15  200200

我想获取这些数据的一个子集,这样我就只有每个 'obj_id' 的最新(最大 'data_date''value'

我想出了一个解决方案,但感觉很脏。我想知道是否有人有更好的方法。我敢肯定我一定错过了一些通过熊猫来做到这一点的简单方法。

我的方法本质上是按如下方式进行分组、排序、检索和重组:

row_arr = []
for grp, grp_df in df.groupby('obj_id'):
    row_arr.append(dfg.sort('data_date', ascending = False)[:1].values[0])

df_new = DataFrame(row_arr, columns = ('obj_id', 'data_date', 'value'))

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    如果“obj_id”的数量非常多,您需要对整个数据帧进行排序,然后删除重复项以获取最后一个元素。

    sorted = df.sort_index(by='data_date')
    result = sorted.drop_duplicates('obj_id', keep='last').values
    

    这应该会更快(抱歉我没有测试),因为你不必做自定义的 agg 函数,当有大量键时会很慢。您可能认为对整个数据帧进行排序会更糟糕,但在实践中,python 排序速度很快,而原生循环很慢。

    【讨论】:

    • 这很有魅力,其他答案对我来说都有问题,而且速度也快了很多。
    • 这对我来说比 pdifranc 的答案快了一个数量级以上。这个问题以各种形式存在于SO上。我会把他们都指向这个答案。只需一张便条FutureWarning: the take_last=True keyword is deprecated, use keep='last' instead
    【解决方案2】:

    这是另一种可能的解决方案。不知道这是否是最快的(我怀疑..),因为我没有将它与其他方法进行基准测试。

    df.loc[df.groupby('obj_id').data_date.idxmax(),:]
    

    【讨论】:

    • 这是一个很好的方法,在这种情况和其他情况下对我有用。
    • 一个不错的通用解决方案,但与其他一些方法相比相当慢
    【解决方案3】:

    我喜欢 crampbum 的回答,可能这样更快(抱歉,尚未对此进行测试,但我避免对所有内容进行排序):

    df.groupby('obj_id').agg(lambda df: df.values[df['data_date'].values.argmax()])
    

    它使用 numpys "argmax" 函数来查找出现最大值的行索引。

    【讨论】:

    • 我在一个包含 24735 行的数据帧上测试了速度,分为 16 组(顺便说一句:来自planethunter.org 的数据集),结果为 12.5 ms(argmax)和 17.5 ms(排序)时间。所以这两种解决方案都非常快:-)而且我的数据集似乎太小了;-)
    【解决方案4】:

    groupby 对象上的aggregate() method 可用于在一个步骤中从 groupby 对象创建新的 DataFrame。 (不过,我不知道有一种更简洁的方法来提取 DataFrame 的第一行/最后一行。)

    In [12]: df.groupby('obj_id').agg(lambda df: df.sort('data_date')[-1:].values[0])
    Out[12]: 
             data_date  value
    obj_id                   
    1       2009-07-28  15860
    2       2011-10-01  35200
    4       2011-11-01  59500
    

    您还可以对单个列执行聚合,在这种情况下,聚合函数适用于 Series 对象。

    In [25]: df.groupby('obj_id')['value'].agg({'diff': lambda s: s.max() - s.min()})
    Out[25]: 
              diff
    obj_id        
    1            0
    2       165000
    4        34640
    

    【讨论】:

      【解决方案5】:

      更新thetainted1's answer,因为正如tommy.carstensen 指出的那样,一些功能现在有未来的警告。这对我有用:

      sorted = df.sort_values(by='data_date')
      
      result = sorted.drop_duplicates('obj_id', keep='last')
      

      【讨论】:

        【解决方案6】:

        我相信已经找到了基于此线程中的更合适的解决方案。 但是我的使用数据框的应用功能而不是聚合。 它还返回一个新的数据框,其列与原始数据框相同。

        df = pd.DataFrame({
        'CARD_NO': ['000', '001', '002', '002', '001', '111'],
        'DATE': ['2006-12-31 20:11:39','2006-12-27 20:11:53','2006-12-28 20:12:11','2006-12-28 20:12:13','2008-12-27 20:11:53','2006-12-30 20:11:39']})
        
        print df 
        df.groupby('CARD_NO').apply(lambda df:df['DATE'].values[df['DATE'].values.argmax()])
        

        原创

        CARD_NO                 DATE
        0     000  2006-12-31 20:11:39
        1     001  2006-12-27 20:11:53
        2     002  2006-12-28 20:12:11
        3     002  2006-12-28 20:12:13
        4     001  2008-12-27 20:11:53
        5     111  2006-12-30 20:11:39
        

        返回的数据框:

        CARD_NO
        000        2006-12-31 20:11:39
        001        2008-12-27 20:11:53
        002        2006-12-28 20:12:13
        111        2006-12-30 20:11:39
        

        【讨论】:

          猜你喜欢
          • 2020-05-20
          • 2022-01-05
          • 2018-06-09
          • 2023-03-19
          • 2018-07-15
          • 2015-12-11
          • 1970-01-01
          • 2023-02-01
          • 2016-07-09
          相关资源
          最近更新 更多