熊猫数据框:如何根据行中的值复制其他列中的某些列

时间:2017-09-18 15:55:07

标签: python pandas dataframe

您好我正在处理如下数据框:

   yearStart    2014  2015  2016  2017  2018  2019  
0    2015        0    150   200     0     0     0       
1    2016        0     0    200   140    35    10       
2    2017        0     0     0     20    12    12

通常情况下,这是一份包含所有费用的财务报告,在签订合同时开始(专栏开始'年份开始')并持续数年

   yearStart Year+0  Year+1  Year+2  Year+3  Year+4 ... Year+N
0     2015    150     200      0      0       0       
1     2016    200     140     35      0       0       
2     2017    20      12      12      0       0      

如何重新整形数据框,以便从合约的第一年开始以相对日期样式存储数据。

我在每一行上尝试了iterrows()并将相关列复制到另一个数据框中,但这需要花费太多时间......

编辑:

好吧,我忘了说在合同的相关期间可能有一年,价值是0,不应该忘记。要考虑的列在yearStart中的日期和结束之间,作为参数给出。输入更像是这样:

   0    2015        0    150   200     0    13     0       
   1    2016        0     0    200   140    35     0    10   
   2    2017        0     0     0     20    12     0    12

谢谢

2 个答案:

答案 0 :(得分:1)

使用带有过滤的apply创建新行,然后分配新的列名称

df1 = df.apply(lambda x: pd.Series(x[x!=0].values), 1).fillna(0).astype(int)
df1.columns = df.columns.tolist()[:len(df1.columns)]
df1 = df1.reindex(columns=df.columns, fill_value=0)
print (df1)
   yearStart  2014  2015  2016  2017  2018  2019
0       2015   150   200     0     0     0     0
1       2016   200   140    35    10     0     0
2       2017    20    12    12     0     0     0

如果可以使用更大的DataFrame,请使用Divakar函数justify_rows

def justify_rows(a, side='left'):
    mask = a>0
    justified_mask = np.sort(mask,1)
    if side=='left':
        justified_mask = justified_mask[:,::-1]
    out = np.zeros_like(a) 
    out[justified_mask] = a[mask]
    return out

df1 = pd.DataFrame(justify_rows(df.values), columns=df.columns, index=df.index)
print (df1)
   yearStart  2014  2015  2016  2017  2018  2019
0       2015   150   200     0     0     0     0
1       2016   200   140    35    10     0     0
2       2017    20    12    12     0     0     0

如果想要字符串Years

cols = ['yearStart'] + ['Year+{}'.format(x) for x in range(len(df.columns) - 1)]
df1 = pd.DataFrame(justify_rows(df.values), columns=cols, index=df.index)
print (df1)
   yearStart  Year+0  Year+1  Year+2  Year+3  Year+4  Year+5
0       2015     150     200       0       0       0       0
1       2016     200     140      35      10       0       0
2       2017      20      12      12       0       0       0

编辑:

对于第二个解决方案,需要this solution来选择第一个连续的0

def justify_rows(a, side='left'):
    mask = a.cumsum(axis=1) != 0
    print (mask)
    justified_mask = np.sort(mask,1)
    print (justified_mask)
    if side=='left':
        justified_mask = justified_mask[:,::-1]
    out = np.zeros_like(a) 
    out[justified_mask] = a[mask]
    print (out)
    return out

cols = ['Year+{}'.format(x) for x in range(len(df.columns) - 1)]
df1 = df[['yearStart']].join(pd.DataFrame(justify_rows(df.values[:, 1:]),
                                          columns=cols, index=df.index))
print (df1)
   yearStart  Year+0  Year+1  Year+2  Year+3  Year+4  Year+5
0       2015     150     200       0      13       0       0
1       2016     200     140      35       0       0       0
2       2017      20      12       0       0       0       0

答案 1 :(得分:1)

df=df.replace({0:np.nan})
df=df.loc[:,df.isnull().sum(0).ne(3)]

选项1:

df.apply(lambda x : (x[x.notnull()].values.tolist()+x[x.isnull()].values.tolist()),1).fillna(0)

出[145]:

   yearStart   2015   2016  2017  2018  2019
0     2015.0  150.0  200.0   0.0   0.0   0.0
1     2016.0  200.0  140.0  35.0  10.0   0.0
2     2017.0   20.0   12.0  12.0   0.0   0.0

选项2:

df.apply(lambda x: sorted(x, key=pd.isnull), 1).fillna(0)


Out[145]: 
   yearStart   2015   2016  2017  2018  2019
0     2015.0  150.0  200.0   0.0   0.0   0.0
1     2016.0  200.0  140.0  35.0  10.0   0.0
2     2017.0   20.0   12.0  12.0   0.0   0.0