Python Pandas:平衡不平衡的数据集(用于面板分析)

时间:2018-11-22 23:40:47

标签: python pandas dataframe

我知道这可能很容易做到。我可以在Stata中做到这一点,但我正在尝试使用Python。

我有一个不平衡的大数据集。看起来像这样:

enter image description here

我需要获取如下数据集:

enter image description here

欢迎任何指导。非常感谢!

3 个答案:

答案 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_indexreindex将{year}的数据用作pd.MultiIndex.from_productreset_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”,您可以将groupbytransformmax一起使用来获取值,对于列“ 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()