答案 0 :(得分:1)
这是对 Ben's 答案的轻微修改。
每当您尝试创建平衡面板时,我发现最简单的方法是使用 stack
/unstack
,而不是重新定义索引:
import pandas as pd
import numpy as np
df = pd.DataFrame({'year':[2003, 2004, 2002, 2004, 2005, 2006],
'city_code':['a']*2+['b']*4,
'total_tax':np.random.randint(100, 1000, 6)},
index=pd.Index(data=[9] * 2 + [54] * 4, name='id_inf'))
# Create balanced panels with NaNs using stack/unstack
df = df.set_index('year', append=True).unstack().stack(dropna=False)
print(df)
这将使用 NaN 创建您的平衡面板:
city_code total_tax
id_inf year
9 2002 NaN NaN
2003 a 110.0
2004 a 324.0
2005 NaN NaN
2006 NaN NaN
54 2002 b 885.0
2003 NaN NaN
2004 b 419.0
2005 b 275.0
2006 b 732.0
您还可以使用 unstack
/stack
在列或行中应用 fillna()
方法:
# Fillna() works within columns/rows; stack and unstack appropriately to use this method
df = df.unstack('id_inf')
df['city_code'] = df['city_code'].fillna(method='ffill').fillna(method='bfill')
df = df.stack().swaplevel().sort_index()
print(df)
city_code total_tax
id_inf year
9 2002 a NaN
2003 a 110.0
2004 a 324.0
2005 a NaN
2006 a NaN
54 2002 b 885.0
2003 b NaN
2004 b 419.0
2005 b 275.0
2006 b 732.0
答案 1 :(得分:0)
一种方法是使用set_index
和reindex
将{year}的数据用作pd.MultiIndex.from_product
,reset_index
来将'year'设置为另一个索引级别。
具有相同结构的示例数据框:
import pandas as pd
df = pd.DataFrame( {'year':[2003,2004,2002,2004,2005,2006],
'city_code':['a']*2+['b']*4,
'total_tax':pd.np.random.randint(100,1000,6)},
index=pd.Index(data=[9]*2+[54]*4,name='id_inf'))
print(df)
city_code total_tax year
id_inf
9 a 417 2003
9 a 950 2004
54 b 801 2002
54 b 218 2004
54 b 886 2005
54 b 855 2006
现在,您可以使用以下方法创建df_balanced
:
df_balanced = (df.set_index('year',append=True)
.reindex(pd.MultiIndex.from_product([df.index.unique(),
range(df.year.min(),df.year.max()+1)],
names=['id_inf','year']))
.reset_index(level=1))
您会得到:
print (df_balanced)
year city_code total_tax
id_inf
9 2002 NaN NaN
9 2003 a 417.0
9 2004 a 950.0
9 2005 NaN NaN
9 2006 NaN NaN
54 2002 b 801.0
54 2003 NaN NaN
54 2004 b 218.0
54 2005 b 886.0
54 2006 b 855.0
要填充NaN
,可以使用不同的方法,但是这里有两种方法。对于列“ city_code”,您可以将groupby
和transform
与max
一起使用来获取值,对于列“ total_tax”,只需将fillna
与0一起使用,例如:
df_balanced['city_code'] = df_balanced.groupby(level=0)['city_code'].transform(max)
df_balanced['total_tax'] = df_balanced['total_tax'].fillna(0)
print (df_balanced)
year city_code total_tax
id_inf
9 2002 a 0.0
9 2003 a 417.0
9 2004 a 950.0
9 2005 a 0.0
9 2006 a 0.0
54 2002 b 801.0
54 2003 b 0.0
54 2004 b 218.0
54 2005 b 886.0
54 2006 b 855.0
答案 2 :(得分:0)
这种方式可能更容易理解,并且可以轻松适应更复杂的场景。
假设我们有一个不平衡的面板 df
和三个要扩展的维度:城市、年、月。
import itertools
import pandas as pd
balanced_idx = pd.DataFrame(
itertools.product(
set(dfm['ctry_iso']), # Dimension 1: All country codes
range(1970, 2021), # Dimension 2: All years
range(1, 13) # Dimension 3: All months
)
, columns=['ctry_iso', 'year', 'month'] # Assign column names
)
所以现在我们有了一个平衡的索引。如您所见,这种方式的好处是您始终可以拥有任意数量的维度。
接下来的两个步骤只是将我们的数据合并到平衡索引上,然后填充缺失值。
balanced_df = balanced_idx.merge(
df,
on=['ctry_iso', 'year', 'month'],
how='left'
)
# Fill 1: Simply filled by zero.
balanced_df['var1'].fillna(0, inplace=True)
# Fill 2: Filled by last / next non-missing value.
balanced_df['var2'] = balanced_df.groupby(['ctry_iso'])['var2'].ffill().bfill()