如何将数据框从长转换为宽,索引中的值按年份分组?
Posted
技术标签:
【中文标题】如何将数据框从长转换为宽,索引中的值按年份分组?【英文标题】:How to convert a dataframe from long to wide, with values grouped by year in the index? 【发布时间】:2021-01-06 13:39:26 【问题描述】:下面的代码与我使用的以前的 csv 一起工作,两个 csv 的列数相同,并且列具有相同的名称。
有效的 csv 数据 here
没有here的csv数据
这个错误是什么意思?为什么会出现此错误?
from pandas import read_csv
from pandas import DataFrame
from pandas import Grouper
from matplotlib import pyplot
series = read_csv('carringtonairtemp.csv', header=0, index_col=0, parse_dates=True, squeeze=True)
groups = series.groupby(Grouper(freq='A'))
years = DataFrame()
for name, group in groups:
years[name.year] = group.values
years = years.T
pyplot.matshow(years, interpolation=None, aspect='auto')
pyplot.show()
错误
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-6-7173fcbe8c08> in <module>
6 # display(group.head())
7 # print(group.values[:10])
----> 8 years[name.year] = group.values
e:\Anaconda3\lib\site-packages\pandas\core\frame.py in __setitem__(self, key, value)
3038 else:
3039 # set column
-> 3040 self._set_item(key, value)
3041
3042 def _setitem_slice(self, key: slice, value):
e:\Anaconda3\lib\site-packages\pandas\core\frame.py in _set_item(self, key, value)
3114 """
3115 self._ensure_valid_index(value)
-> 3116 value = self._sanitize_column(key, value)
3117 NDFrame._set_item(self, key, value)
3118
e:\Anaconda3\lib\site-packages\pandas\core\frame.py in _sanitize_column(self, key, value, broadcast)
3759
3760 # turn me into an ndarray
-> 3761 value = sanitize_index(value, self.index)
3762 if not isinstance(value, (np.ndarray, Index)):
3763 if isinstance(value, list) and len(value) > 0:
e:\Anaconda3\lib\site-packages\pandas\core\internals\construction.py in sanitize_index(data, index)
745 """
746 if len(data) != len(index):
--> 747 raise ValueError(
748 "Length of values "
749 f"(len(data)) "
ValueError: Length of values (365) does not match length of index (252)
【问题讨论】:
【参考方案1】: 以所示方式迭代创建数据帧的问题是,它需要新列与现有数据帧的长度相匹配,year
,索引。
在较小的数据集中,所有年份都是 365 天,没有缺失天数。
较大的数据集包含 365 天和 366 天的混合长度年份,并且缺少 1990 年和 2020 年的数据,这导致 ValueError: Length of values (365) does not match length of index (252)
。
以下是一个更简洁的脚本,它实现了所需的数据框形状和绘图。
此实现不存在数据长度不等的问题。
import pandas as pd
import matplotlib.pyplot as plt
# links to data
url1 = 'https://raw.githubusercontent.com/trenton3983/stack_overflow/master/data/so_data/2020-09-19%20%2063975678/daily-min-temperatures.csv'
url2 = 'https://raw.githubusercontent.com/trenton3983/stack_overflow/master/data/so_data/2020-09-19%20%2063975678/carringtonairtemp.csv'
# load the data into a DataFrame, not a Series
# parse the dates, and set them as the index
df1 = pd.read_csv(url1, parse_dates=['Date'], index_col=['Date'])
df2 = pd.read_csv(url2, parse_dates=['Date'], index_col=['Date'])
# groupby year and aggregate Temp into a list
dfg1 = df1.groupby(df1.index.year).agg('Temp': list)
dfg2 = df2.groupby(df2.index.year).agg('Temp': list)
# create a wide format dataframe with all the temp data expanded
df1_wide = pd.DataFrame(dfg1.Temp.tolist(), index=dfg1.index)
df2_wide = pd.DataFrame(dfg2.Temp.tolist(), index=dfg2.index)
# plot
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10, 10))
ax1.matshow(df1_wide, interpolation=None, aspect='auto')
ax2.matshow(df2_wide, interpolation=None, aspect='auto')
【讨论】:
【参考方案2】:您收到此错误是因为这些组的行数不同。因此,首先您在空数据框中添加一个具有 252 个值的列,现在数据框的大小为 252。然后您尝试添加一个具有 365 个值的列,其大小与 252 不同。这就是您收到此错误的原因。代码工作的数据帧每年(组)具有相同数量的值(364)。但现在你有:
1990-12-31 252
1991-12-31 365
1992-12-31 366
...
例如,假设我们有这个 DataFrame:
A
0 1
1 2
2 3
如果我们尝试添加一个包含两个值的列,我们会得到这个错误:
df['B']=[1,2]
ValueError: Length of values does not match the length of the index
只要我们添加相同数量的值就可以了:
df['B']=[1,2,3]
【讨论】:
以上是关于如何将数据框从长转换为宽,索引中的值按年份分组?的主要内容,如果未能解决你的问题,请参考以下文章
R语言使用reshape函数将dataframe数据从长表变换为宽表(long format to wide format)
R语言使用tidyr包的spread函数将dataframe数据从长表变换为宽表(long format to wide format)