Home > Net >  Split a column into multiple columns pandas depending on the values in a column
Split a column into multiple columns pandas depending on the values in a column

Time:05-09

I have a dataframe as shown below.

                     A          B
timestamp       
2022-05-09 09:28:00  0          45
2022-05-09 09:28:01  3          NaN
2022-05-09 09:28:02  4          30
2022-05-09 09:28:03  5          20
2022-05-09 09:28:04  8          10

I want the values in column B to be split and represented in multiple columns depending on the values in column A as shown below.

                     A_0  A_3  A_4  A_5  A_8
timestamp       
2022-05-09 09:28:00  45   NaN  NaN  NaN  NaN
2022-05-09 09:28:01  NaN  NaN  NaN  NaN  NaN
2022-05-09 09:28:02  NaN  NaN  30   NaN  NaN
2022-05-09 09:28:03  NaN  NaN  NaN  20   NaN
2022-05-09 09:28:04  NaN  NaN  NaN  NaN  10

Since the splitting depends on the values present in another column and there is no delimiter present, the solution to split the column depending on a delimiter does not work.

Thanks in advance!

EDIT: If I want to do it for multiple columns, for eg:


                     A          B       C     D
timestamp       
2022-05-09 09:28:00  0          45      3     20
2022-05-09 09:28:01  3          NaN     2     15
2022-05-09 09:28:02  4          30      5     34
2022-05-09 09:28:03  5          20      4     NaN
2022-05-09 09:28:04  8          10      8     NaN

And I want to convert to this

                     A_0  A_3  A_4  A_5  A_8  C_3  C_2  C_5  C_4  C_8
timestamp       
2022-05-09 09:28:00  45   NaN  NaN  NaN  NaN  20    NaN  NaN  NaN  NaN  
2022-05-09 09:28:01  NaN  NaN  NaN  NaN  NaN  NaN   15   NaN  NaN  NaN  
2022-05-09 09:28:02  NaN  NaN  30   NaN  NaN  NaN   NaN  NaN  48   NaN  
2022-05-09 09:28:03  NaN  NaN  NaN  20   NaN  NaN   NaN  NaN  NaN  NaN  
2022-05-09 09:28:04  NaN  NaN  NaN  NaN  10   NaN   NaN  NaN  NaN  NaN  

Is this still possible or do I have to do separetly and merge or concat them?

CodePudding user response:

Use DataFrame.set_index with append=True for MultiIndex and reshape by Series.unstack:

df1=df.set_index('A',append=True)['B'].unstack().add_prefix('A_').rename_axis(columns=None)
print (df1)
                      A_0  A_3   A_4   A_5   A_8
timestamp                                       
2022-05-09 09:28:00  45.0  NaN   NaN   NaN   NaN
2022-05-09 09:28:01   NaN  NaN   NaN   NaN   NaN
2022-05-09 09:28:02   NaN  NaN  30.0   NaN   NaN
2022-05-09 09:28:03   NaN  NaN   NaN  20.0   NaN
2022-05-09 09:28:04   NaN  NaN   NaN   NaN  10.0

Or use DataFrame.reset_index with DataFrame.pivot:

df1 = df.reset_index().pivot('timestamp','A','B').add_prefix('A_').rename_axis(columns=None)

EDIT from comment under answer - use DataFrame.pivot_table with aggregate function, default is mean with DataFrame.reindex for add timestamp with missing values in B column:

print (df)
                     A     B
timestamp                   
2022-05-09 09:28:00  0  45.0 <-duplicated timestamp, A values
2022-05-09 09:28:00  0  30.0 <-duplicated timestamp, A values
2022-05-09 09:28:01  3   NaN
2022-05-09 09:28:02  4  30.0
2022-05-09 09:28:03  5  20.0
2022-05-09 09:28:04  8  10.0



df2 = (df.reset_index()
         .pivot_table(index='timestamp',columns='A',values='B', aggfunc='mean')
         .add_prefix('A_')
         .reindex(df.index.unique())
         .rename_axis(columns=None))

print (df2)
                      A_0   A_4   A_5   A_8
timestamp                                  
2022-05-09 09:28:00  37.5   NaN   NaN   NaN
2022-05-09 09:28:01   NaN   NaN   NaN   NaN
2022-05-09 09:28:02   NaN  30.0   NaN   NaN
2022-05-09 09:28:03   NaN   NaN  20.0   NaN
2022-05-09 09:28:04   NaN   NaN   NaN  10.0

Aggregation by mean used for first part of solution - row with missing values is not removed:

df2 = (df.groupby(['timestamp','A'])['B']
         .mean()
         .unstack()
         .add_prefix('A_')
         .rename_axis(columns=None))
print (df2)
                      A_0  A_3   A_4   A_5   A_8
timestamp                                       
2022-05-09 09:28:00  37.5  NaN   NaN   NaN   NaN
2022-05-09 09:28:01   NaN  NaN   NaN   NaN   NaN
2022-05-09 09:28:02   NaN  NaN  30.0   NaN   NaN
2022-05-09 09:28:03   NaN  NaN   NaN  20.0   NaN
2022-05-09 09:28:04   NaN  NaN   NaN   NaN  10.0

EDIT: Dirst create pairs with same values after _ with rename:

df = df.rename(columns={'A':'V_A', 'C':'V_C',
                        'B':'I_A', 'D':'I_C'})

Then use wide_to_long:

df3 = (pd.wide_to_long(df.reset_index(), stubnames=['V', 'I'],
                     i='timestamp', 
                     j='i', 
                     sep='_',
                     suffix=r'\w '
                     ).reset_index()
      )
print (df3)
             timestamp  i  V     I
0  2022-05-09 09:28:00  A  0  45.0
1  2022-05-09 09:28:01  A  3   NaN
2  2022-05-09 09:28:02  A  4  30.0
3  2022-05-09 09:28:03  A  5  20.0
4  2022-05-09 09:28:04  A  8  10.0
5  2022-05-09 09:28:00  C  3  20.0
6  2022-05-09 09:28:01  C  2  15.0
7  2022-05-09 09:28:02  C  5  34.0
8  2022-05-09 09:28:03  C  4   NaN
9  2022-05-09 09:28:04  C  8   NaN

And last aggregate mean with reshape:

df4 = (df3.groupby(['timestamp','V','i'])['I']
          .mean()
          .unstack(['i','V'])
          .sort_index(axis=1)
         )
df4.columns = df4.columns.map(lambda x: f'{x[0]}_{x[1]}')
print (df4)
                      A_0  A_3   A_4   A_5   A_8   C_2   C_3  C_4   C_5  C_8
timestamp                                                                   
2022-05-09 09:28:00  45.0  NaN   NaN   NaN   NaN   NaN  20.0  NaN   NaN  NaN
2022-05-09 09:28:01   NaN  NaN   NaN   NaN   NaN  15.0   NaN  NaN   NaN  NaN
2022-05-09 09:28:02   NaN  NaN  30.0   NaN   NaN   NaN   NaN  NaN  34.0  NaN
2022-05-09 09:28:03   NaN  NaN   NaN  20.0   NaN   NaN   NaN  NaN   NaN  NaN
2022-05-09 09:28:04   NaN  NaN   NaN   NaN  10.0   NaN   NaN  NaN   NaN  NaN

CodePudding user response:

Using a simple pivot would only work when there is no duplicated combinations for timestamp/A :

df.reset_index().pivot('timestamp', 'A', 'B').add_prefix('A')

output:

                      A_0  A_3   A_4   A_5   A_8
timestamp                                       
2022-05-09 09:28:00  45.0  NaN   NaN   NaN   NaN
2022-05-09 09:28:01   NaN  NaN   NaN   NaN   NaN
2022-05-09 09:28:02   NaN  NaN  30.0   NaN   NaN
2022-05-09 09:28:03   NaN  NaN   NaN  20.0   NaN
2022-05-09 09:28:04   NaN  NaN   NaN   NaN  10.0

If you have duplicated indices you need to decide on how to handle it. Either aggregate using pivot_table or deduplicate the duplicates first:

output:

(df.reset_index()
   .pivot_table(index='timestamp', columns='A', values='B',
                aggfunc='sum') # chose the method to aggregate, default is 'mean'
)
  • Related