【问题标题】:group by pandas dataframe and condition按熊猫数据框和条件分组
【发布时间】:2019-05-15 12:02:33
【问题描述】:

我的问题基于thread,我们将 pandas 数据框的值分组并从每个组中选择最新的(按日期):

    id     product   date
0   220    6647     2014-09-01 
1   220    6647     2014-09-03 
2   220    6647     2014-10-16
3   826    3380     2014-11-11
4   826    3380     2014-12-09
5   826    3380     2015-05-19
6   901    4555     2014-09-01
7   901    4555     2014-10-05
8   901    4555     2014-11-01

使用以下

df.loc[df.groupby('id').date.idxmax()]

但是,假设我想包含一个条件,即我只想从+/- 5 天内每个组中选择最新的(按日期)。即,分组后我想在以下组中找到最新的:

0   220    6647     2014-09-01 #because only these two are within +/- 5 days of each other
1   220    6647     2014-09-03 

2   220    6647     2014-10-16 #spaced more than 5 days apart the above two records

3   826    3380     2014-11-11

.....

产生

    id  product       date
1  220     6647 2014-09-03 
2  220     6647 2014-10-16
3  826     3380 2014-11-11
4  826     3380 2014-12-09
5  826     3380 2015-05-19
5  826     3380 2015-05-19
6  901     4555 2014-09-01
7  901     4555 2014-10-05
8  901     4555 2014-11-01

价格数据集:

    id     product   date           price
0   220    6647     2014-09-01      100   #group 1
1   220    6647     2014-09-03      120   #group 1   --> pick this
2   220    6647     2014-09-05      0     #group 1
3   826    3380     2014-11-11      150   #group 2   --> pick this
4   826    3380     2014-12-09      23    #group 3   --> pick this
5   826    3380     2015-05-12      88    #group 4   --> pick this
6   901    4555     2015-05-15      32    #group 4   
7   901    4555     2015-10-05      542   #group 5   --> pick this
8   901    4555     2015-11-01      98    #group 6   --> pick this

【问题讨论】:

    标签: python pandas group-by grouping


    【解决方案1】:

    我认为您需要通过applylist comprehensionbetween 创建组,然后通过factorize 转换为数字组,最后使用loc + idxmax 的解决方案:

    df['date'] = pd.to_datetime(df['date'])
    
    df = df.reset_index(drop=True)
    td = pd.Timedelta('5 days')
    
    def f(x):
        x['g']  = [tuple((x.index[x['date'].between(i - td, i + td)])) for i in x['date']]
        return x
    
    df2 = df.groupby('id').apply(f)
    df2['g'] = pd.factorize(df2['g'])[0]
    print (df2)
        id  product       date  price  g
    0  220     6647 2014-09-01    100  0
    1  220     6647 2014-09-03    120  0
    2  220     6647 2014-09-05      0  0
    3  826     3380 2014-11-11    150  1
    4  826     3380 2014-12-09     23  2
    5  826     3380 2015-05-12     88  3
    6  901     4555 2015-05-15     32  4
    7  901     4555 2015-10-05    542  5
    8  901     4555 2015-11-01     98  6
    
    df3 = df2.loc[df2.groupby('g')['price'].idxmax()]
    print (df3)
        id  product       date  price  g
    1  220     6647 2014-09-03    120  0
    3  826     3380 2014-11-11    150  1
    4  826     3380 2014-12-09     23  2
    5  826     3380 2015-05-12     88  3
    6  901     4555 2015-05-15     32  4
    7  901     4555 2015-10-05    542  5
    8  901     4555 2015-11-01     98  6
    

    【讨论】:

    • 这是一个很好的解决方案,谢谢。假设有第四列,价格。是否可以推广解决方案,使得在给定的group 的 5 天记录中,我们选择价格最高的产品?
    • @N08 - 因为需要再次过滤我认为您可以添加您的解决方案df1.loc[df1.groupby('id').date.idxmax()]
    • 但是我们不是还需要根据s进行过滤吗?
    • @N08 - 但应用的解决方案在较大的 DataFrame 中速度较慢
    • 是的,同意。不幸的是真的不容易矢量化,因为总是有必要将组的每个值与组的所有值进行比较。
    【解决方案2】:

    或者使用双线:

    df2=pd.to_numeric(df.groupby('id')['date'].diff(-1).astype(str).str[:-25]).abs().fillna(6)
    print(df.loc[df2.index[df2>5].tolist()])
    

    输出:

        id  product       date
    1  220     6647 2014-09-03
    2  220     6647 2014-10-16
    3  826     3380 2014-11-11
    4  826     3380 2014-12-09
    5  826     3380 2015-05-19
    6  901     4555 2014-09-01
    7  901     4555 2014-10-05
    8  901     4555 2014-11-01
    

    所以使用diff并使用字符串切片进行切片,并对所有值求绝对值,然后删除小于5的值,获取那些索引,然后获取df中的索引。

    【讨论】:

      猜你喜欢
      • 2017-05-08
      • 2019-02-15
      • 2021-12-13
      • 2013-02-28
      • 1970-01-01
      • 2022-01-25
      • 2019-10-14
      • 2014-07-11
      • 1970-01-01
      相关资源
      最近更新 更多