MRHarv
MRHarv

Reputation: 503

Transforming pandas dataframe, where column entries are column headers

My dataset has 12 columns, X1-X6 and Y1-Y6. The variables X and Y match to each other - the first record means: 80 parts of A, 10 parts of C, 2 parts of J and 8 parts of K (each row has 100 total).

I would like to be able to transform my dataset into a dataset in which the entries in columns X1-X6 are now the headers. See before and after datasets below.

My dataset (before):

   X1 X2 X3   X4   X5   X6    Y1    Y2    Y3    Y4    Y5   Y6
0   A  C  J    K  NaN  NaN  80.0  10.0   2.0   8.0   NaN  NaN
1   F  N  O  NaN  NaN  NaN   2.0  25.0  73.0   NaN   NaN  NaN
2   A  H  J    M  NaN  NaN  70.0   6.0  15.0   9.0   NaN  NaN
3   B  I  K    P  NaN  NaN   0.5   1.5   2.0  96.0   NaN  NaN
4   A  B  F    H    O    P  83.0   4.0   9.0   2.0   1.0  1.0
5   A  B  F    G  NaN  NaN   1.0  16.0   9.0  74.0   NaN  NaN
6   A  B  D    F    L  NaN  95.0   2.0   1.0   1.0   1.0  NaN
7   B  F  H    P  NaN  NaN   0.2   0.4   0.4  99.0   NaN  NaN
8   A  D  F    L  NaN  NaN  35.0  12.0  30.0  23.0   NaN  NaN
9   A  B  F    I    O  NaN  95.0   0.3   0.1   1.6   3.0  NaN
10  B  E  G  NaN  NaN  NaN  10.0  31.0  59.0   NaN   NaN  NaN
11  A  F  G    L  NaN  NaN  24.0   6.0  67.0   3.0   NaN  NaN
12  A  C  I  NaN  NaN  NaN  65.0  30.0   5.0   NaN   NaN  NaN
13  A  F  G    L  NaN  NaN  55.0   6.0   4.0  35.0   NaN  NaN
14  A  F  J    K    L  NaN  22.0   3.0  12.0   0.8  62.2  NaN
15  B  F  I    P  NaN  NaN   0.6   1.2   0.2  98.0   NaN  NaN
16  A  B  F    H    O  NaN  27.0   6.0  46.0  13.0   8.0  NaN

The dataset I'd like to transform to:

   A     B     C     D     E     F     G     H    I     J    K     L    M  \
0 80.0  NaN  10.0   NaN   NaN   NaN   NaN   NaN  NaN   2.0  8.0   NaN  NaN   
1 NaN   NaN   NaN   NaN   NaN   2.0   NaN   NaN  NaN   NaN  NaN   NaN  NaN   
2 70.0  NaN   NaN   NaN   NaN   NaN   NaN   6.0  NaN  15.0  NaN   NaN  9.0   
3 NaN   0.5   NaN   NaN   NaN   NaN   NaN   NaN  1.5   NaN  2.0   NaN  NaN   
4 83.0  4.0   NaN   NaN   NaN   9.0   NaN   2.0  NaN   NaN  NaN   NaN  NaN   
5 1.0   16.0   NaN   NaN   NaN   9.0  74.0   NaN  NaN   NaN  NaN   NaN  NaN   
6 95.0   2.0   NaN   1.0   NaN   1.0   NaN   NaN  NaN   NaN  NaN   1.0  NaN   
7 NaN   0.2   NaN   NaN   NaN   0.4   NaN   0.4  NaN   NaN  NaN   NaN  NaN   
8 35.0   NaN   NaN  12.0   NaN  30.0   NaN   NaN  NaN   NaN  NaN  23.0  NaN   
9 95.0   0.3   NaN   NaN   NaN   0.1   NaN   NaN  1.6   NaN  NaN   NaN  NaN   
10 NaN  10.0   NaN   NaN  31.0  NaN   59.0   NaN  NaN   NaN  NaN   NaN  NaN   
11 24.0  NaN   NaN   NaN   NaN   6.0  67.0   NaN  NaN   NaN  NaN   3.0  NaN   
12 65.0  NaN  30.0   NaN   NaN   NaN   NaN   NaN  5.0   NaN  NaN   NaN  NaN   
13 55.0  NaN   NaN   NaN   NaN   6.0   4.0   NaN  NaN   NaN  NaN  35.0  NaN   
14 22.0  NaN   NaN   NaN   NaN   3.0   NaN   NaN  NaN  12.0  0.8  62.2  NaN   
15 NaN   0.6   NaN   NaN   NaN   1.2   NaN   NaN  0.2   NaN  NaN   NaN  NaN   
16 27.0  6.0   NaN   NaN   NaN  46.0   NaN  13.0  NaN   NaN  NaN   NaN  NaN   

      N     O     P  
0    NaN   NaN   NaN  
1   25.0  73.0   NaN  
2    NaN   NaN   NaN  
3    NaN   NaN  96.0  
4    NaN   1.0   1.0  
5    NaN   NaN   NaN  
6    NaN   NaN   NaN  
7    NaN   NaN  99.0  
8    NaN   NaN   NaN  
9    NaN   3.0   NaN  
10   NaN   NaN   NaN  
11   NaN   NaN   NaN  
12   NaN   NaN   NaN  
13   NaN   NaN   NaN  
14   NaN   NaN   NaN  
15   NaN   NaN  98.0  
16   NaN   8.0   NaN 

Upvotes: 4

Views: 73

Answers (2)

run-out
run-out

Reputation: 3184

One way to handle this. Loop through each row, splitting the dataframe in half using iloc. Then build a new dictionary using zip, then create a resulting dataframe.

df_dict = {x: list(zip(df.iloc[x,0:6], df.iloc[x,6:12])) for x in range(df.shape[0])}
df1 = pd.DataFrame.from_dict(pd_dict, orient='index')

df1.sort_index(1)

      A     B       C       F   H   I   J       K   M   N        O      P   nan
0   80.0    NaN     10.0    NaN NaN NaN 2.0     8.0 NaN NaN      NaN    NaN NaN
1   NaN     NaN     NaN     2.0 NaN NaN NaN     NaN NaN 25.0    73.0    NaN NaN
2   70.0    NaN     NaN     NaN 6.0 NaN 15.0    NaN 9.0 NaN      NaN    NaN NaN
3   NaN     0.5     NaN     NaN NaN 1.5 NaN     2.0 NaN NaN      NaN    96. NaN
4   83.0    4.0     NaN     9.0 2.0 NaN NaN     NaN NaN NaN      1.0    1.0 NaN

Upvotes: 0

Serge Ballesta
Serge Ballesta

Reputation: 148975

As you know that you want the Xi part to contain the column names for the new dataframe, while the Yi part would be the value, it is enough to change every line in a dict where Xi is the key and Yi the value. Then you use the list of that dictionnaries to feed the new dataframe:

data = list(df.apply(lambda x: {x['X'+ str(i)]: x['Y'+str(i)] for i in range(1,7)
                                if x['X'+str(i)]!= 'NaN'}, axis=1))

resul = pd.DataFrame(data)
print(resul)

gives:

       A     B     C     D     E     F  ...     K     L    M     N     O     P
0   80.0   NaN  10.0   NaN   NaN   NaN  ...   8.0   NaN  NaN   NaN   NaN   NaN
1    NaN   NaN   NaN   NaN   NaN   2.0  ...   NaN   NaN  NaN  25.0  73.0   NaN
2   70.0   NaN   NaN   NaN   NaN   NaN  ...   NaN   NaN  9.0   NaN   NaN   NaN
3    NaN   0.5   NaN   NaN   NaN   NaN  ...   2.0   NaN  NaN   NaN   NaN  96.0
4   83.0   4.0   NaN   NaN   NaN   9.0  ...   NaN   NaN  NaN   NaN   1.0   1.0
5    1.0  16.0   NaN   NaN   NaN   9.0  ...   NaN   NaN  NaN   NaN   NaN   NaN
6   95.0   2.0   NaN   1.0   NaN   1.0  ...   NaN   1.0  NaN   NaN   NaN   NaN
7    NaN   0.2   NaN   NaN   NaN   0.4  ...   NaN   NaN  NaN   NaN   NaN  99.0
8   35.0   NaN   NaN  12.0   NaN  30.0  ...   NaN  23.0  NaN   NaN   NaN   NaN
9   95.0   0.3   NaN   NaN   NaN   0.1  ...   NaN   NaN  NaN   NaN   3.0   NaN
10   NaN  10.0   NaN   NaN  31.0   NaN  ...   NaN   NaN  NaN   NaN   NaN   NaN
11  24.0   NaN   NaN   NaN   NaN   6.0  ...   NaN   3.0  NaN   NaN   NaN   NaN
12  65.0   NaN  30.0   NaN   NaN   NaN  ...   NaN   NaN  NaN   NaN   NaN   NaN
13  55.0   NaN   NaN   NaN   NaN   6.0  ...   NaN  35.0  NaN   NaN   NaN   NaN
14  22.0   NaN   NaN   NaN   NaN   3.0  ...   0.8  62.2  NaN   NaN   NaN   NaN
15   NaN   0.6   NaN   NaN   NaN   1.2  ...   NaN   NaN  NaN   NaN   NaN  98.0
16  27.0   6.0   NaN   NaN   NaN  46.0  ...   NaN   NaN  NaN   NaN   8.0   NaN

[17 rows x 16 columns]

Upvotes: 2

Related Questions