如何在 pandas 的列中使用带有多个值的 groupby?

E. *_*nci 5 python dataframe pandas

我有一个如下所示的数据框,

import pandas as pd

data = {
    'brand': ['Mercedes', 'Renault', 'Ford', 'Mercedes', 'Mercedes', 'Mercedes', 'Renault'],
    'model': ['X', 'Y', 'Z', 'X', 'X', 'X', 'Q'],
    'year': [2011, 2010, 2009, 2010, 2012, 2020, 2011],
    'price': [None, 1000.4, 2000.3, 1000.0, 1100.3, 3000.5, None]
}

df = pd.DataFrame(data)
print(df)

      brand model  year   price
0  Mercedes     X  2011     NaN
1   Renault     Y  2010  1000.4
2      Ford     Z  2009  2000.3
3  Mercedes     X  2010  1000.0
4  Mercedes     X  2012  1100.3
5  Mercedes     X  2020  3000.5
6   Renault     Q  2011     NaN
Run Code Online (Sandbox Code Playgroud)

这是测试您的解决方案的另一个案例,

data = {
    'brand': ['Mercedes', 'Mercedes', 'Mercedes', 'Mercedes', 'Mercedes'], 
    'model': ['X', 'X', 'X', 'X', 'X'], 'year': [2017, 2018, 2018, 2019, 2019], 
    'price': [None, None, None, 1000.0, 1200.50]
}
Run Code Online (Sandbox Code Playgroud)

预期输出,

data = {
    'brand': ['Mercedes', 'Mercedes', 'Mercedes', 'Mercedes', 'Mercedes'], 
    'model': ['X', 'X', 'X', 'X', 'X'], 'year': [2017, 2018, 2018, 2019, 2019], 
    'price': [None, None, None, 1000.0, 1200.50]
}
Run Code Online (Sandbox Code Playgroud)

我想用包含year-1、year和year+1以及相同品牌和型号的观察值的平均值来填充缺失值。例如,梅赛德斯X车型在2011年的价格为空。当我查看数据时,

2011 - 1 = 2010
2011 + 1 = 2012

The 4th observation -> Mercedes,X,2010,1000.0
The 5th observation -> Mercedes,X,2012,1100.3

The mean -> (1000.0 + 1100.3) / 2 = 1050.15
Run Code Online (Sandbox Code Playgroud)

我尝试过如下操作,

      brand model  year    price
0  Mercedes     X  2017      NaN
1  Mercedes     X  2018  1100.25
2  Mercedes     X  2018  1100.25
3  Mercedes     X  2019  1000.00
4  Mercedes     X  2019  1200.50
Run Code Online (Sandbox Code Playgroud)

但是这个方案对于90,000行27列来说需要很长时间,那么有没有更有效的方案呢?例如,我可以使用groupby值“year-1”、“year”、“year+1”、“brand”和“model”吗?

提前致谢。

Yol*_*_21 1

def fill_it(x):
    return df[(df.brand==df.iat[x,0])&(df.model==df.iat[x,1])&((df.year==df.iat[x,2]-1)|(df.year==df.iat[x,2]+1))].price.mean()



df = df.apply(lambda x: x.fillna(fill_it(x.name)), axis=1)
df



Output 1:
    brand   model   year    price
0   Mercedes    X   2011    1050.15
1   Renault     Y   2010    1000.40
2   Ford        Z   2009    2000.30
3   Mercedes    X   2010    1000.00
4   Mercedes    X   2012    1100.30
5   Mercedes    X   2020    3000.50
6   Renault     Q   2011    NaN


Output 2:
    brand   model   year    price
0   Mercedes    X   2017    NaN
1   Mercedes    X   2018    1100.25
2   Mercedes    X   2018    1100.25
3   Mercedes    X   2019    1000.00
4   Mercedes    X   2019    1200.50

Run Code Online (Sandbox Code Playgroud)

快了 3 倍

df.loc[df.price.isna(), 'price'] = df[df.price.isna()].apply(lambda x: x.fillna(fill_it(x.name)), axis=1)
Run Code Online (Sandbox Code Playgroud)

我尝试了另一种方法,使用pd.rolling它,它的速度更快(在具有 70k 行的数据帧上运行时间为 200 毫秒)。输出仍然如您所愿。

df.year = pd.to_datetime(df.year, format='%Y')
df.sort_values('year', inplace=True)
df.groupby(['brand', 'model']).apply(lambda x: x.fillna(x.rolling('1095D',on='year', center=True).mean())).sort_index()
Run Code Online (Sandbox Code Playgroud)