根据数据框中的排序值旋转多行

时间:2019-11-20 02:03:41

标签: python pandas pandas-groupby

我正在使用看起来像这样的数据框:

df = pd.DataFrame({'ID':['A','A','A','A','B','B','B','B'],'X':[1.2,2.1,3.8,4.5,5.8,6.2,7,8.2],'Y':[10,20,30,40,50,60,70,80],'IsTrue':[1,1,0,0,1,0,0,1],'IdxVar':[1,0,0,0,0,0,0,1]})
df["DistanceToIdx"] = np.sqrt((df.X - df.X[df.groupby('ID')['IdxVar'].transform('idxmax')].reset_index(drop=True))**2 \
                        +(df.Y - df.Y[df.groupby('ID')['IdxVar'].transform('idxmax')].reset_index(drop=True))**2)

我正在尝试基于IdxVar创建一个新的df,每个ID值具有一行。很简单

newdf = df.loc[df.IdxVar==1,:]

我希望我的新列为X0_1, X0_2, X1_1, X0_2,其中Xi_j可以看作是Xfor i = IsTrue(0或1)和{{ 1}}指示j的排序索引(DistanceToIdx指示给定ID中具有X0_1和最低X的{​​{1}}值)。

我可以通过IsTrue = 0进行此操作:

DistanceToIdx

这将提供所需的输出,但是如果我想将其应用于更多变量,然后在此处显示,然后遍历100,000个组,则我的循环耗时太长。

我想知道是否有一种方法可以仅通过groupby函数来加快速度。我最初的想法只是想弄清楚数据透视功能,但是由于我想根据现有的行对新列进行排序,因此,我对基于文档的有效性不太有把握。

2 个答案:

答案 0 :(得分:1)

您已经创建了newdf。我提出了使用nsmallest的解决方案,以获取每个组的2个最小值unstack并展平多索引列。最后,合并回newdf

df1 = (df.set_index('X').groupby(['ID', 'IsTrue']).DistanceToIdx.nsmallest(2).
          reset_index(level=-1).drop('DistanceToIdx', 1))
s = df1.groupby(level=[0,1]).cumcount().add(1)
df2 = df1.set_index(s, append=True).unstack([1,2]).sort_index(level=2, axis=1)
df2.columns = df2.columns.map('{0[0]}{0[1]}_{0[2]}'.format)

df_final = newdf.merge(df2.reset_index(), on='ID')


Out[239]:

  ID    X   Y  IsTrue  IdxVar  DistanceToIdx  X0_1  X1_1  X0_2  X1_2
0  A  1.2  10       1       1            0.0   3.8   1.2   4.5   2.1
1  B  8.2  80       1       1            0.0   7.0   8.2   6.2   5.8

答案 1 :(得分:0)

我会使用GroupBy.cumcount 创建O索引 并能够透视表(DataFrame.pivot_table)区分4列。 然后只需使用DataFrame.join

将其附加到j所在的框架
IdxVar==1

输出

new_df=df.copy()
#creating columns to pivot_table and set the name of the columns
new_df['id2']=df.groupby(['ID','IsTrue']).IsTrue.cumcount()+1

#Selecting IDxVar1 --->df1
df1=df[df.IdxVar.eq(1)]

#Using pivot_table
#new_df=new_df.sort_values(by=['IsTrue','DistanceToIdx'],ascending=True)
df2=new_df.pivot_table(index='ID',columns=['id2','IsTrue'],values='X')

#join both dataframes
new_df=df1.join(df2,on='ID')

#creating the names of columns
new_df.columns =df.columns.tolist() + [f'X{i}_{j}' for j,i in df2.columns]
print(new_df)