Pandas Dataframe行基于值间隔进行平均

时间:2018-03-30 16:19:22

标签: python pandas dataframe

我有一个DataFrame,其中包含数千个汽车的列表。每辆车都有一个开始年份列和一个结束年份列,表示汽车流通的年份间隔。每辆车在整个时期内都有一个平均油耗列,如下:

df_cars
+-----+------------+----------+--------------------------+
| Car | Start year | End year | Average fuel consumption |
+-----+------------+----------+--------------------------+
| 1   | 2002       | 2025     | 10.0                     |
+-----+------------+----------+--------------------------+
| 2   | 1995       | 2008     | 12.5                     |
+-----+------------+----------+--------------------------+
| 3   | 2005       | 2017     | 8.5                      |
+-----+------------+----------+--------------------------+

在2000年至2015年期间,我想获得每年运营的车队的平均油耗" Y"。因此,如果汽车具有开始年份< Y和结束年份>是的,它应该包含在该年的船队平均数中。显然,大多数汽车将出现在车队平均数年内。

截至目前,我正在进行循环,但速度相当慢。

for y in range(2000, 2015):
    df_cars[(df_cars["Start year"]<=int(y))&(df_cars["End year"]>=int(y))]["Average fuel consumption"].mean(axis=0)

有更快的方法吗? 谢谢。

1 个答案:

答案 0 :(得分:1)

以下是使用collections.Counter的一种方式。

矢量化,但似乎仍然提供了13倍的性能提升。

有一个pandonic但仍然是循环的替代here,但我找不到矢量化实现。

import pandas as pd
from collections import Counter

df = pd.DataFrame([[1, 2002, 2025, 10.0],
                   [2, 1995, 2008, 12.5],
                   [3, 2005, 2017, 8.5]],
                  columns=['Car', 'StartYear', 'EndYear', 'AvgFuelConsumption'])

def jp(df):

    # first get range of years
    year_range = range(df['StartYear'].min(), df['EndYear'].max()+1)

    res = pd.DataFrame(index=year_range, columns=['AvgFuelConsumption'])

    # use collections.Counter for sums and counts
    c_sum = Counter()
    c_count = Counter()
    for idx, car, start, end, fuel in df.itertuples():
        for i in range(start, end+1):
            c_sum[i] += fuel
            c_count[i] += 1

    # calculate averages by year
    c_res = {y: c_sum[y] / c_count[y] for y in c_sum}

    # create dataframe from dictionary
    res = pd.DataFrame.from_dict(c_res, orient='index')

    return res

def original(df):

    res = pd.DataFrame(index=range(2000, 2026), columns=['AvgFuelConsumption'])

    for y in range(2000, 2026):
        res.loc[y, 'AvgFuelConsumption'] = df[(df["StartYear"]<=int(y))&(df["EndYear"]>=int(y))]["AvgFuelConsumption"].mean(axis=0)

    return res

%timeit jp(df)        # 4.17ms
%timeit original(df)  # 54.8ms