【问题标题】:Pandas Dataframe rows average based on value intervalPandas Dataframe 行的平均值基于值区间
【发布时间】:2023-03-10 20:10:01
【问题描述】:

我有一个 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)

有更快的方法吗? 谢谢。

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

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

    它没有矢量化,但似乎仍能提供 13 倍的性能提升。

    有一个泛滥但仍然循环的替代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
    

    【讨论】:

    • 谢谢。确实快得多!
    猜你喜欢
    • 1970-01-01
    • 2021-11-19
    • 2016-01-18
    • 2021-05-05
    • 1970-01-01
    • 2019-08-29
    • 2016-01-08
    • 2020-11-14
    • 2014-12-01
    相关资源
    最近更新 更多