Given a df as shown below, and assume the value under column lapse
is unique and range from 0 to 18. However, some of the values is not available within this range. For this example, the value 0
,16
and 18
is missing.
lapse (a, i) (a, j) (b, k) c
0 2.0 0.423655 0.645894 0.437587 0.891773
1 4.0 0.963663 0.383442 0.791725 0.528895
2 6.0 0.568045 0.925597 0.071036 0.087129
3 8.0 0.020218 0.832620 0.778157 0.870012
4 10.0 0.978618 0.799159 0.461479 0.780529
5 12.0 0.118274 0.639921 0.143353 0.944669
6 14.0 0.521848 0.414662 0.264556 0.774234
The objective is to create a surrogate rows of these is missing value, and append it to the original df
. Such that, the output should be as below
lapse (a, i) (a, j) (b, k) c
0 0.0 NaN NaN NaN NaN
0 2.0 0.423655 0.645894 0.437587 0.891773
1 4.0 0.963663 0.383442 0.791725 0.528895
2 6.0 0.568045 0.925597 0.071036 0.087129
3 8.0 0.020218 0.832620 0.778157 0.870012
4 10.0 0.978618 0.799159 0.461479 0.780529
5 12.0 0.118274 0.639921 0.143353 0.944669
6 14.0 0.521848 0.414662 0.264556 0.774234
1 16.0 NaN NaN NaN NaN
2 18.0 NaN NaN NaN NaN
The following code snippet is able to answer the above objective. However, in actual implementation, the data frame is of bigger magnitude and I am wonder whether there is better way , or pandas built-in of doing this?
Line to generate to original df
import numpy as np
import pandas as pd
nshape=5
increment=2
max_val=20
np.random.seed(0)
aran=np.arange(0,max_val,increment).astype(int)
nshape=aran.shape[0]
arr=np.concatenate((aran.reshape(-1,1), np.random.random((nshape,4))), axis=1)
# Extracted only selected, other non selected index are assume case to solve
idx_available=[3, 5, 4, 2, 1, 7, 6]
df=pd.DataFrame(arr[sorted(idx_available),:],columns=['lapse',('a','i'),('a','j'),('b','k'),'c'])
Proposed solution
name_other=[i for i in df.columns.tolist() if i!='lapse']
lapse_available=df['lapse'].to_numpy()
lapse_not_available = np.setdiff1d(aran,lapse_available)
an_array = np.empty((len(lapse_not_available),len(name_other)))
an_array[:] = np.NaN
arr2=np.concatenate((lapse_not_available.reshape(-1,1), an_array), axis=1)
df2=pd.DataFrame(arr2,columns=['lapse'] name_other)
df=pd.concat([df,df2],axis=0).sort_values(by=['lapse'])
CodePudding user response:
You can also use:
df.set_index('lapse', inplace=True)
df = df.reindex(np.arange(0,20,2)).reset_index()
OUTPUT
lapse (a, i) (a, j) (b, k) c
0 0 NaN NaN NaN NaN
1 2 0.423655 0.645894 0.437587 0.891773
2 4 0.963663 0.383442 0.791725 0.528895
3 6 0.568045 0.925597 0.071036 0.087129
4 8 0.020218 0.832620 0.778157 0.870012
5 10 0.978618 0.799159 0.461479 0.780529
6 12 0.118274 0.639921 0.143353 0.944669
7 14 0.521848 0.414662 0.264556 0.774234
8 16 NaN NaN NaN NaN
9 18 NaN NaN NaN NaN
CodePudding user response:
You can merge
:
df.merge(pd.DataFrame({'lapse': np.arange(0,20,2)}), how='right')
Output:
lapse (a, i) (a, j) (b, k) c
0 0.0 NaN NaN NaN NaN
1 2.0 0.423655 0.645894 0.437587 0.891773
2 4.0 0.963663 0.383442 0.791725 0.528895
3 6.0 0.568045 0.925597 0.071036 0.087129
4 8.0 0.020218 0.832620 0.778157 0.870012
5 10.0 0.978618 0.799159 0.461479 0.780529
6 12.0 0.118274 0.639921 0.143353 0.944669
7 14.0 0.521848 0.414662 0.264556 0.774234
8 16.0 NaN NaN NaN NaN
9 18.0 NaN NaN NaN NaN
Note: merge
or other operations based on __eq__
on floats, e.g. np.setdiff1d
, must be carried on with care.
CodePudding user response:
Referencig crono's answer you can use the following tools from pandas:
Index
- To create the complete list of lapses your dataframe is going to use. Index doc
set_index
- Set your column lapse as index to facilitate the dataframe transformation. set_index doc
reindex
- The main part, to merge your dataframe with the complete list o lapses, reindex will automatically fill the missing rows with NaN and keep the ones that already exist. reindex doc
reset_index
- Will return your lapse to a normal column instead of index. reset_index doc