Home > database >  Pandas DataFrame and grouping Pandas Series data into individual columns by value
Pandas DataFrame and grouping Pandas Series data into individual columns by value

Time:08-24

I am hoping someone can help me optimize the following Python/Pandas code. My code works, but I know there must be a cleaner and faster way to perform the operation under consideration.

I am looking for an optimized strategy because my use case will involve 16 unique ADC Types, as opposed to 4 in the example below. Also, my initial Pandas Series (i.e. ADC Type column), will be several 100,000 data points in length, rather than 8 in the example below.

import numpy as np
import pandas as pd
from enum import Enum

data_dict = {"RAW": [4000076160, 5354368, 4641792, 4289860736,
                     4136386944, 5440384, 4772864, 4289881216],
             "ADC_TYPE": [3, 7, 8, 9,
                          3, 7, 8, 9]}
df = pd.DataFrame(data_dict)
print(df)

The initial DataFrame (i.e. df) is:

          RAW  ADC_TYPE
0  4000076160         3
1     5354368         7
2     4641792         8
3  4289860736         9
4  4136386944         3
5     5440384         7
6     4772864         8
7  4289881216         9

I then manipulate the DataFrame above using the following code:

unique_types = df["ADC_TYPE"].unique()

dict_concat = {"RAW": [],
               "ADC_TYPE_3": [],
               "ADC_TYPE_7": [],
               "ADC_TYPE_8": [],
               "ADC_TYPE_9": []}
df_concat = pd.DataFrame(dict_concat)

for adc_type in unique_types:
    df_group = df.groupby(["ADC_TYPE"]).get_group(adc_type).rename(columns={"ADC_TYPE": f"ADC_TYPE_{adc_type}"})
    df_concat = pd.concat([df_concat, df_group])

print(df_concat.sort_index())

The returned DataFrame (i.e. df_concat) is displayed below. The ordering of RAW and the associated ADC Type values must remain unchanged. I need the return DataFrame to look just like the DataFrame below.

            RAW  ADC_TYPE_3  ADC_TYPE_7  ADC_TYPE_8  ADC_TYPE_9
0  4.000076e 09         3.0         NaN         NaN         NaN
1  5.354368e 06         NaN         7.0         NaN         NaN
2  4.641792e 06         NaN         NaN         8.0         NaN
3  4.289861e 09         NaN         NaN         NaN         9.0
4  4.136387e 09         3.0         NaN         NaN         NaN
5  5.440384e 06         NaN         7.0         NaN         NaN
6  4.772864e 06         NaN         NaN         8.0         NaN
7  4.289881e 09         NaN         NaN         NaN         9.0

Thank you for your consideration.

CodePudding user response:

This is just a pivot table with a prefix.

Edit: To preserve sorting, you can reindex from the original dataframe

df = pd.DataFrame({'RAW': {0: 4000076160,
  1: 5354368,
  2: 4641792,
  3: 4289860736,
  4: 4136386944,
  5: 5440384,
  6: 4772864,
  7: 4289881216},
 'ADC_TYPE': {0: 3, 1: 7, 2: 8, 3: 9, 4: 3, 5: 7, 6: 8, 7: 9}})

out = df.pivot(index='RAW', columns = 'ADC_TYPE', values='ADC_TYPE').add_prefix('ACC_TYPE_').reset_index().rename_axis(None, axis=1)
out = out.set_index('RAW').reindex(df['RAW']).reset_index()

Output

          RAW  ACC_TYPE_3  ACC_TYPE_7  ACC_TYPE_8  ACC_TYPE_9
0  4000076160         3.0         NaN         NaN         NaN
1     5354368         NaN         7.0         NaN         NaN
2     4641792         NaN         NaN         8.0         NaN
3  4289860736         NaN         NaN         NaN         9.0
4  4136386944         3.0         NaN         NaN         NaN
5     5440384         NaN         7.0         NaN         NaN
6     4772864         NaN         NaN         8.0         NaN
7  4289881216         NaN         NaN         NaN         9.0

CodePudding user response:

Here is a way using str.get_dummies()

df2 = df.set_index('RAW')['ADC_TYPE'].astype(str).str.get_dummies()

(df2.mul(pd.to_numeric(df2.columns),axis=1)
.mask(lambda x: x.eq(0))
.rename('ADC_TYPE_{}'.format,axis=1)
.reset_index())

Here is a slightly different way using pd.get_dummies()

df2 = pd.get_dummies(df.set_index('RAW'),columns = ['ADC_TYPE'])

df2.mul((df2.columns.str.split('_').str[-1]).astype(int)).where(lambda x: x.ne(0))

You can also use set_index() and unstack()

(df.set_index(['RAW',df['ADC_TYPE'].astype(str).map('ADC_TYPE_{}'.format)])['ADC_TYPE']
.unstack().reindex(df['RAW']).reset_index())

Output:

          RAW  ADC_TYPE_3  ADC_TYPE_7  ADC_TYPE_8  ADC_TYPE_9
0  4000076160         3.0         NaN         NaN         NaN
1     5354368         NaN         7.0         NaN         NaN
2     4641792         NaN         NaN         8.0         NaN
3  4289860736         NaN         NaN         NaN         9.0
4  4136386944         3.0         NaN         NaN         NaN
5     5440384         NaN         7.0         NaN         NaN
6     4772864         NaN         NaN         8.0         NaN
7  4289881216         NaN         NaN         NaN         9.0

CodePudding user response:

I liked the idea of using get_dummies, so I modified it a bit:

df = (pd.get_dummies(df, 'ADC_TYPE', '_', columns=['ADC_TYPE'])
        .replace(1, np.nan)
        .apply(lambda x: x.fillna(df['ADC_TYPE']))
        .replace(0, np.nan))

Output:

          RAW  ADC_TYPE_3  ADC_TYPE_7  ADC_TYPE_8  ADC_TYPE_9
0  4000076160         3.0         NaN         NaN         NaN
1     5354368         NaN         7.0         NaN         NaN
2     4641792         NaN         NaN         8.0         NaN
3  4289860736         NaN         NaN         NaN         9.0
4  4136386944         3.0         NaN         NaN         NaN
5     5440384         NaN         7.0         NaN         NaN
6     4772864         NaN         NaN         8.0         NaN
7  4289881216         NaN         NaN         NaN         9.0

CodePudding user response:

Using crosstab:

out = pd.crosstab(
    df["RAW"], df["ADC_TYPE"], values=df["ADC_TYPE"], aggfunc="first"
).rename_axis(None, axis=1)
out.columns = out.columns.map("ADC_TYPE_{}".format)
out = out.reindex(df["RAW"]).reset_index()

print(out):

          RAW  ADC_TYPE_3  ADC_TYPE_7  ADC_TYPE_8  ADC_TYPE_9
0  4000076160         3.0         NaN         NaN         NaN
1     5354368         NaN         7.0         NaN         NaN
2     4641792         NaN         NaN         8.0         NaN
3  4289860736         NaN         NaN         NaN         9.0
4  4136386944         3.0         NaN         NaN         NaN
5     5440384         NaN         7.0         NaN         NaN
6     4772864         NaN         NaN         8.0         NaN
7  4289881216         NaN         NaN         NaN         9.0
  • Related