根据特定单元格中的值移动pd.dataframe的行

时间:2019-12-12 06:47:17

标签: python pandas dataframe

假设我们有一个结构如下的数据框:

df = pd.DataFrame({
         'Year':[2017, 2019, 2018, 2017, 2017, 2017],
         'B':[4,5,4,5,5,4],
         'C':[0,0,0,0,0,7],
         'D':[0,1,3,5,7,1],
         'E':[5,3,6,9,2,4],

总体思路是将每一行移动一次,与“年份”列中的值相对应,2017年是基准年,应在(年份-2017年)单元格上将每一行右移,并用零(0),例如:

df = pd.DataFrame({
         'Year':[2017, 2019, 2018, 2017, 2017, 2017],
         'B':[4,0,0,5,5,4],
         'C':[0,0,4,0,0,7],
         'D':[0,5,0,5,7,1],
         'E':[5,0,3,9,2,4],
         'F':[0,1,6,0,0,0],
         'G':[0,3,0,0,0,0],
})

ps:实际上,我们接下来需要对结果行进行成对求和,以便每一列的“年”都相同

仅当我们对0和2行求和时才适用。然后应该是1和3,依此类推

enter image description here 因此,也许有一些熊猫功能可以帮助您完成这项任务,而无需预先移动...

2 个答案:

答案 0 :(得分:1)

如果默认情况下在熊猫中使用shift,则最后一列会丢失。因此有必要先添加由缺失值填充的新列-列数取决于非2017年值的差异。

df = df.set_index('Year')

diff = np.setdiff1d(df.index.dropna().unique(), [2017]).astype(int)
print (diff)
[2018 2019]

df = df.assign(**{f'new{x}':np.nan for x in range(max(diff-2017))})

然后,您可以循环使用shift并按索引中的年份按DataFrame.loc进行过滤:

for y in diff:
    df.loc[y, :] = df.astype(float).shift(y - 2017, axis=1).loc[y, :]

最后一次替换丢失的值,转换为整数并将索引转换为列:

df = df.fillna(0).astype(int).reset_index()
print (df)
   Year  B  C  D  E  new0  new1
0  2017  4  0  0  5     0     0
1  2019  0  0  5  0     1     3
2  2018  0  4  0  3     6     0
3  2017  5  0  5  9     0     0
4  2017  5  0  7  2     0     0
5  2017  4  7  1  4     0     0

编辑:

另一列的解决方案:

df = pd.DataFrame({
         'new':list('abcdef'),
         'Year':[2017, 2019, 2018, 2017, 2017, 2017],
         'B':[4,5,4,5,5,4],
         'C':[0,0,0,0,0,7],
         'D':[0,1,3,5,7,1],
         'E':[5,3,6,9,2,4]})
print (df)
  new  Year  B  C  D  E
0   a  2017  4  0  0  5
1   b  2019  5  0  1  3
2   c  2018  4  0  3  6
3   d  2017  5  0  5  9
4   e  2017  5  0  7  2
5   f  2017  4  7  1  4

df = df.set_index(['new','Year'])

diff = np.setdiff1d(df.index.get_level_values('Year').dropna().unique(), [2017]).astype(int)
print (diff)
[2018 2019]

df1 = pd.DataFrame(index=df.index, columns=['new{}'.format(x) for x in range(max(diff-2017))])
df = pd.concat([df, df1], axis=1) 
print (df)
          B  C  D  E new0 new1
new Year                      
a   2017  4  0  0  5  NaN  NaN
b   2019  5  0  1  3  NaN  NaN
c   2018  4  0  3  6  NaN  NaN
d   2017  5  0  5  9  NaN  NaN
e   2017  5  0  7  2  NaN  NaN
f   2017  4  7  1  4  NaN  NaN

for y in diff:
    idx = pd.IndexSlice
    df.loc[idx[:, y], :] = df.astype(float).shift(y - 2017, axis=1).loc[idx[:, y], :]

df = df.fillna(0).astype(int).reset_index()
print (df)
  new  Year  B  C  D  E  new0  new1
0   a  2017  4  0  0  5     0     0
1   b  2019  0  0  5  0     1     3
2   c  2018  0  4  0  3     6     0
3   d  2017  5  0  5  9     0     0
4   e  2017  5  0  7  2     0     0
5   f  2017  4  7  1  4     0     0

答案 1 :(得分:1)

我以编程方式创建了从第一个df帧到最后一个df帧的操作步骤。我这样做是因为看来您可能正在寻找以编程方式进行该操作的方法,这可能会对最终结果有所帮助。有了一点了解,我可能可以使此过程更容易:

import pandas as pd
import numpy as np
df = pd.DataFrame({
         'Year':[2017, 2019, 2018, 2017, 2017, 2017],
         'B':[4,5,4,5,5,4],
         'C':[0,0,0,0,0,7],
         'D':[0,1,3,5,7,1],
         'E':[5,3,6,9,2,4],})

df.insert(column='F',loc=len(df)-1,value=np.zeros(len(df),dtype=int)) 
df.insert(column='G',loc=len(df)-1,value=np.zeros(len(df),dtype=int)) 
df1 = df.T
cols =df1.iloc[0]
df1.columns = cols
df1.drop('Year', inplace=True)
df1.iloc[0:, [1]] =  np.roll(df1.iloc[0:, [1]], shift=2)
df1.iloc[0:, [2]] =  np.roll(df1.iloc[0:, [2]], shift=1)

df = df1.T.reset_index() 
res = df.iloc[2] + df.iloc[0]
df = df.append(res, ignore_index=True)
df['Year'][6]= 'res'

输出:

   Year  B  C  D  E  G  F
0  2017  4  0  0  5  0  0
1  2019  0  0  5  0  1  3
2  2018  0  4  0  3  6  0
3  2017  5  0  5  9  0  0
4  2017  5  0  7  2  0  0
5  2017  4  7  1  4  0  0
6   res  4  4  0  8  6  0