如何根据另一列中的条件转置一列?



我确信以前有人问过这个问题(因为这是一个常见问题),但我找不到它。

所以我的数据帧如下所示:

ID     Name
1      A
1      B
2      X
2      Y
2      Z

我想要这种格式(我不在乎列名)

1    A    B
2    X    Y   Z  and so on...

通过DataFrame.set_indexGroupBy.cumcount创建MultiIndex,并通过Series.unstackindex列的DataFrame.reset_index重新塑造形状:

df1 = (df.set_index(['ID',df.groupby('ID').cumcount()])['Name']
.unstack(fill_value='')
.reset_index())
print (df1)
ID  0  1  2
0   1  A  B   
1   2  X  Y  Z

DataFrame表演:

np.random.seed(123)
N = 1000
L = list('abcdefghijklmno')
df = pd.DataFrame({'Name': np.random.choice(L, N),
'ID':np.random.randint(100, size=N)}).sort_values('ID')
#print (df)
In [15]: %%timeit
...: df_new=df.groupby('ID')['Name'].apply(lambda x: ','.join(list(x))).reset_index()
...: df_new.join(df_new.pop('Name').str.split(",",expand=True))
...: 
22 ms ± 411 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [16]: %%timeit
...: df1 = (df.set_index(['ID',df.groupby('ID').cumcount()])['Name']
...:          .unstack(fill_value='')
...:          .reset_index())
...: 
6.05 ms ± 212 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [17]: %%timeit
...: df.set_index('ID').groupby('ID').apply(lambda x: x.reset_index(drop=True).T).reset_index(level=1,drop=True)
...: 
151 ms ± 1.25 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

你可以做这样的事情:

df_new=df.groupby('ID')['Name'].apply(lambda x: ','.join(list(x))).reset_index()
df_new.join(df_new.pop('Name').str.split(",",expand=True))
ID  0  1     2
0   1  A  B  None
1   2  X  Y     Z

可以通过以下代码创建所需的内容。

data = [[1,'A'] , [1 , 'B'] , [2 , 'X'] , [2 , 'Y'] , [2 , 'Z']]  
df = pd.DataFrame(data , columns=['ID' , 'Name'])
id_list = df['ID'][~df['ID'].duplicated()]
t_rows = []
max_val_num = 0
for id_ in id_list:
row = df[df['ID'] == id_]['Name'].tolist()
t_rows.append(row)
if len(row) >= max_val_num:
max_val_num = len(row)
df_transform = pd.DataFrame(t_rows , columns=['col_'+str(i) for i in range(max_val_num)])  
print(df_transform)

最新更新