【发布时间】:2016-10-04 15:52:14
【问题描述】:
我有一个如下所示的数据集:
我使用 pandas.read_csv 将 Year 和 Country 列作为索引导入到 pandas 数据框中。 我需要做的是将时间步长从每 5 年更改为每年一次,并插入所述值,我真的不知道如何做到这一点。 我正在学习 R 和 python,因此非常感谢任何一种语言的帮助。
【问题讨论】:
标签: python dataframe interpolation panel-data
我有一个如下所示的数据集:
我使用 pandas.read_csv 将 Year 和 Country 列作为索引导入到 pandas 数据框中。 我需要做的是将时间步长从每 5 年更改为每年一次,并插入所述值,我真的不知道如何做到这一点。 我正在学习 R 和 python,因此非常感谢任何一种语言的帮助。
【问题讨论】:
标签: python dataframe interpolation panel-data
如果为 DataFrame 提供 DatetimeIndex,则可以利用 df.resample 和 df.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]'。我是不是找错地方了,还是你读了源代码才想出这些?
datetime64的理解主要来自于docs.scipy.org/doc/numpy/reference/arrays.datetime.html加上很多鬼混。文档提到(并且 dtype 名称 datetime64 强烈暗示)底层数据类型是 8 字节整数。因此,为了在 datetime64s 上进行数值数学运算,有时需要使用 astype('i8') 将 datetime64 转换为其基础整数值。 Code 列 displayed here 显示可能的 datetime64[...] dtypes。
(df['Year'].astype('i8')-1970).view('datetime64[Y]') 的一个更易读的替代方案是pd.to_datetime(df['Year'], format='%Y')。但是,对于大型系列,它的速度要慢得多。
df.resample('A').mean() 正在做什么的解释。不过,我不确定我是否解释得很好,所以一定要read the docs。
这是一个艰难的过程,但我想我做到了。
这是一个带有示例数据框的示例:
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()
有点棘手的问题。有兴趣看看是否有人有更好的解决方案
【讨论】:
首先,重新索引框架。然后使用df.apply和Series.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)
【讨论】:
df = df.interpolate() df = df.ffill()