将pandas数据框与数据透视表

时间:2018-02-05 18:58:39

标签: python pandas merge

我想要合并2个数据。

df1是一个包含合同列表的pandas数据框,其中'year'是合同执行的年份,'o_id'是指该合同来自的组织的id。

df2是一个数据透视表,由多年来组织的问题组成(其中年份是审核组织问题的年份)。 P_1和P_2参考问题1和问题2.

df1

c_id | o_id | year |
====================
101  | 10   | 2013 |
102  | 10   | 2014 |
103  | 10   | 2015 |
103  | 10   | 2016 |
121  | 12   | 2013 |
122  | 12   | 2014 |
123  | 12   | 2015 |
123  | 12   | 2016 |

df2

       P_1                | P_2                 
year | 2013 | 2014 | 2015 | 2013 | 2014 | 2015 |
id   | 
================================================
10   | 1    | 0    | 0    | 0    | 0    | 0    |
12   | 0    | 1    | 0    | 1    | 1    | 0    |

目的是合并这两个数据集,以便捕获每个合同相对于合同年份的问题的“历史”>执行(合并'df1 ['o_id'] = df2 ['id'])。

请注意,我不能包含执行合同的年份的历史记录(例如,2015年合同只能使用2014年及之前的历史记录)。

我希望最终输出看起来像这样:

id | year | 2013_P_1 | 2014_P_1 | 2015_P_1 | 2013_P_2 | 2014_P_2 | 2015_P_2 
===============================================================================
10 | 2013 | NA       | NA       | NA       | NA       | NA       | NA
10 | 2014 | 1        | NA       | NA       | 0        | NA       | NA
10 | 2015 | 1        | 0        | NA       | 0        | 0        | NA    
10 | 2016 | 1        | 0        | 0        | 0        | 0        | 0    
12 | 2013 | NA       | NA       | NA       | NA       | NA       | NA
12 | 2014 | 0        | NA       | NA       | 1        | NA       | NA
12 | 2015 | 0        | 1        | NA       | 1        | 1        | NA
12 | 2016 | 0        | 1        | 0        | 1        | 1        | 0

2 个答案:

答案 0 :(得分:1)

首先通过df2stack join重新塑造df1,然后通过自定义函数将NaN替换为值:

df = (df1.drop('c_id', 1)
        .join(df2.stack(0).reset_index(level=1), on='o_id')
        .set_index(['o_id','year', 'level_1']))

def f(x):
    il1 = np.triu_indices(len(x.columns))
    a = x.values.astype(float)
    a[il1] = np.nan
    x = pd.DataFrame(a, columns=x.columns, index=x.index)
    return (x)

df = df.groupby(['o_id','level_1']).apply(f).unstack().sort_index(axis=1, level=1)
df.columns = ['{}_{}'.format(a,b) for a,b in df.columns]
df = df.reset_index()
print (df)
   o_id  year  2013_P_1  2014_P_1  2015_P_1  2013_P_2  2014_P_2  2015_P_2
0    10  2013       NaN       NaN       NaN       NaN       NaN       NaN
1    10  2014       1.0       NaN       NaN       0.0       NaN       NaN
2    10  2015       1.0       0.0       NaN       0.0       0.0       NaN
3    10  2016       1.0       0.0       0.0       0.0       0.0       0.0
4    12  2013       NaN       NaN       NaN       NaN       NaN       NaN
5    12  2014       0.0       NaN       NaN       1.0       NaN       NaN
6    12  2015       0.0       1.0       NaN       1.0       1.0       NaN
7    12  2016       0.0       1.0       0.0       1.0       1.0       0.0

答案 1 :(得分:0)

假设您可以更新pivot_table规范,请考虑转发重复的 Year2 并将 Year 保留在索引中。然后,重命名透视列,然后运行左连接合并:

from itertools import product
...

# NEW PIVOT (ADJUST ACCORDINGLY)
origdf['year2'] = origdf['year']
df2 = origdf.pivot_table(index=['ID', 'year'], columns=['problem'], 
                         values=['year2', 'value'], aggfunc='max')

# RETURN CARTESIAN PRODUCT BETWEEN BOTH PIVOT COLUMN LEVELS
newcols = [str(i[1])+'_'+i[0]
           for i in list(product(df2.columns.levels[0], df2.columns.levels[1]))]

# FLATTEN HIERARCHICAL COLUMNS
df2.columns = df2.columns.get_level_values(0)

# REASSIGN COLUMNS
df2.columns = newcols

# RESET MULTI-INDEX BACK AS DF COLUMNS
df2 = df2.reset_index()

# MERGE, DROP UNNEEDED COLS, RE-ORDER COLUMNS
finaldf = df1.merge(df2, left_on=['o_id'], right_on=['id'], how='left')\
                    .drop(columns=['c_id', 'o_id'])[['id','year'] + newcols]