【问题标题】:How to interpolate between values on a dataframe using Python and/or R如何使用 Python 和/或 R 在数据帧上的值之间进行插值
【发布时间】:2016-10-04 15:52:14
【问题描述】:

我有一个如下所示的数据集:

我使用 pandas.read_csv 将 Year 和 Country 列作为索引导入到 pandas 数据框中。 我需要做的是将时间步长从每 5 年更改为每年一次,并插入所述值,我真的不知道如何做到这一点。 我正在学习 R 和 python,因此非常感谢任何一种语言的帮助。

【问题讨论】:

    标签: python dataframe interpolation panel-data


    【解决方案1】:
    • 如果为 DataFrame 提供 DatetimeIndex,则可以利用 df.resampledf.interpolate('time') 方法。

    • 要使df.index 成为日期时间索引,您可能会想使用set_index('Year')。但是,Year 本身并不是唯一的,因为每个Country 都会重复它。为了调用resample,我们需要一个唯一索引。所以请改用df.pivot

      # convert integer years into `datetime64` values
      In [441]: df['Year'] = (df['Year'].astype('i8')-1970).view('datetime64[Y]')
      In [442]: df.pivot(index='Year', columns='Country')
      Out[442]: 
                      Avg1                      Avg2                
      Country    Australia Austria Belgium Australia Austria Belgium
      Year                                                          
      1950-01-01         0       0       0         0       0       0
      1955-01-01         1       1       1        10      10      10
      1960-01-01         2       2       2        20      20      20
      1965-01-01         3       3       3        30      30      30
      
    • 然后您可以使用 df.resample('A').mean()resample the data 与 yearly 频率。您可以将resample('A') 视为将df 分割成组 间隔 1 年。 resample 返回一个 DatetimeIndexResampler 对象,其 mean 方法通过取平均值来聚合每组中的值。因此 mean() 返回一个 DataFrame,每一年都有一行。由于你原来 df 每 5 年有一个数据,大部分 1 年组将是空的,所以 那些年的平均值返回NaN。如果您的数据始终保持在 5 年间隔,然后您可以使用 .first() 代替 .mean().last() 代替。它们都会返回相同的结果。

      In [438]: df.resample('A').mean()
      Out[438]: 
                      Avg1                      Avg2                
      Country    Australia Austria Belgium Australia Austria Belgium
      Year                                                          
      1950-12-31       0.0     0.0     0.0       0.0     0.0     0.0
      1951-12-31       NaN     NaN     NaN       NaN     NaN     NaN
      1952-12-31       NaN     NaN     NaN       NaN     NaN     NaN
      1953-12-31       NaN     NaN     NaN       NaN     NaN     NaN
      1954-12-31       NaN     NaN     NaN       NaN     NaN     NaN
      1955-12-31       1.0     1.0     1.0      10.0    10.0    10.0
      1956-12-31       NaN     NaN     NaN       NaN     NaN     NaN
      1957-12-31       NaN     NaN     NaN       NaN     NaN     NaN
      1958-12-31       NaN     NaN     NaN       NaN     NaN     NaN
      1959-12-31       NaN     NaN     NaN       NaN     NaN     NaN
      1960-12-31       2.0     2.0     2.0      20.0    20.0    20.0
      1961-12-31       NaN     NaN     NaN       NaN     NaN     NaN
      1962-12-31       NaN     NaN     NaN       NaN     NaN     NaN
      1963-12-31       NaN     NaN     NaN       NaN     NaN     NaN
      1964-12-31       NaN     NaN     NaN       NaN     NaN     NaN
      1965-12-31       3.0     3.0     3.0      30.0    30.0    30.0
      
    • 然后df.interpolate(method='time') 将根据最接近的非 NaN 值及其关联的日期时间索引值线性内插缺失的 NaN 值。


    import numpy as np
    import pandas as pd
    
    countries = 'Australia Austria Belgium'.split()
    year = np.arange(1950, 1970, 5)
    df = pd.DataFrame(
        {'Country': np.repeat(countries, len(year)),
         'Year': np.tile(year, len(countries)),
         'Avg1': np.tile(np.arange(len(year)), len(countries)),
         'Avg2': 10*np.tile(np.arange(len(year)), len(countries))})
    df['Year'] = (df['Year'].astype('i8')-1970).view('datetime64[Y]')
    df = df.pivot(index='Year', columns='Country')
    
    df = df.resample('A').mean()
    df = df.interpolate(method='time')
    
    df = df.stack('Country')
    df = df.reset_index()
    df = df.sort_values(by=['Country', 'Year'])
    print(df)
    

    产量

             Year    Country      Avg1       Avg2
    0  1950-12-31  Australia  0.000000   0.000000
    3  1951-12-31  Australia  0.199890   1.998905
    6  1952-12-31  Australia  0.400329   4.003286
    9  1953-12-31  Australia  0.600219   6.002191
    12 1954-12-31  Australia  0.800110   8.001095
    15 1955-12-31  Australia  1.000000  10.000000
    18 1956-12-31  Australia  1.200328  12.003284
    21 1957-12-31  Australia  1.400109  14.001095
    ...
    

    【讨论】:

    • 美丽。我了解df['Year'] = (df['Year'].astype('i8')-1970).view('datetime64[Y]') 在做什么——但我在任何地方都找不到代码'i8''datetime64[Y]'。我是不是找错地方了,还是你读了源代码才想出这些?
    • @michael_j_ward:我对datetime64的理解主要来自于docs.scipy.org/doc/numpy/reference/arrays.datetime.html加上很多鬼混。文档提到(并且 dtype 名称 datetime64 强烈暗示)底层数据类型是 8 字节整数。因此,为了在 datetime64s 上进行数值数学运算,有时需要使用 astype('i8')datetime64 转换为其基础整数值。 Codedisplayed here 显示可能的 datetime64[...] dtypes。
    • @michael_j_ward (df['Year'].astype('i8')-1970).view('datetime64[Y]') 的一个更易读的替代方案是pd.to_datetime(df['Year'], format='%Y')。但是,对于大型系列,它的速度要慢得多。
    • 我认为我不太了解重新采样部分,特别是 .mean() 部分。您愿意详细说明吗?
    • @MartinValdez:我添加了一点关于df.resample('A').mean() 正在做什么的解释。不过,我不确定我是否解释得很好,所以一定要read the docs
    【解决方案2】:

    这是一个艰难的过程,但我想我做到了。

    这是一个带有示例数据框的示例:

    df = pd.DataFrame({'country': ['australia', 'australia', 'belgium','belgium'], 
                       'year': [1980, 1985, 1980, 1985],
                       'data1': [1,5, 10, 15],
                       'data2': [100,110, 150,160]})
    df = df.set_index(['country','year'])
    countries = set(df.index.get_level_values(0))
    df = df.reindex([(country, year) for country in countries for year in range(1980,1986)])
    df = df.interpolate()
    df = df.reset_index()
    

    对于您的具体数据,假设每个国家/地区都有 1950 年至 2010 年(含)之间每 5 年的数据

    df = pd.read_csv('path_to_data')
    df = df.set_index(['country','year'])
    countries = set(df.index.get_level_values(0))
    df = df.reindex([(country, year) for country in countries for year in range(1950,2011)])
    df = df.interpolate()
    df = df.reset_index()
    

    有点棘手的问题。有兴趣看看是否有人有更好的解决方案

    【讨论】:

      【解决方案3】:

      首先,重新索引框架。然后使用df.applySeries.interpolate

      类似:

      import pandas as pd
      
      df = pd.read_csv(r'folder/file.txt')
      rows = df.shape[0]
      df.index = [x for x in range(0, 5*rows, 5)]
      df = df.reindex(range(0, 5*rows))
      df.apply(pandas.Series.interpolate)
      df.apply(pd.Series.interpolate, inplace=True)
      

      【讨论】:

      • 非常好。最后两行可以只使用 pandas 数据框方法,尽管 df = df.interpolate() df = df.ffill()
      • 鉴于每次一个国家/地区的数据结束时,年份序列都会从 2010 年到 1950 年跳跃,因此当您插入“不连续性”时会变得平滑(抱歉,英语不是我的母语)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-11
      • 1970-01-01
      • 1970-01-01
      • 2020-07-05
      • 1970-01-01
      • 1970-01-01
      • 2016-04-23
      相关资源
      最近更新 更多