Reputation: 127
I have a dataframe that has the following structure:
code name age char
101 NaN NaN ts
101 NaN NaN tt
101 Carl 19 tt
102 NaN NaN ts
102 NaN NaN tt
102 NaN NaN tt
103 NaN NaN ts
103 Aoi 23 tt
103 NaN NaN tt
I would like to copy values from columns "name" and "age" to other rows conditionally on them existing, having the same "code" and "char" being "ts". The resulting dataframe I would like to have is the following:
code name age char
101 Carl 19 ts
101 NaN NaN tt
101 Carl 19 tt
102 NaN NaN ts
102 NaN NaN tt
102 NaN NaN tt
103 Aoi 23 ts
103 Aoi 23 tt
103 NaN NaN tt
Thanks in advance for you help!
Upvotes: 1
Views: 84
Reputation: 2598
In one line:
result = df.copy()
result.update(df.groupby(['code']).bfill()[df['char']=='ts'])
result
code name age char
0 101.0 Carl 19.0 ts
1 101.0 NaN NaN tt
2 101.0 Carl 19.0 tt
3 102.0 NaN NaN ts
4 102.0 NaN NaN tt
5 102.0 NaN NaN tt
6 103.0 Aoi 23.0 ts
7 103.0 Aoi 23.0 tt
8 103.0 NaN NaN tt
Explained
The dataframe is filled wiht rows with 'char' == 'ts'
that have been filled with any available value for the code by doing:
df.groupby(['code']).bfill()
code name age char
0 101 Carl 19.0 ts
1 101 Carl 19.0 tt
2 101 Carl 19.0 tt
3 102 NaN NaN ts
4 102 NaN NaN tt
5 102 NaN NaN tt
6 103 Aoi 23.0 ts
7 103 Aoi 23.0 tt
8 103 NaN NaN tt
df.groupby(['code']).bfill()[df['char']=='ts']
code name age char
0 101 Carl 19.0 ts
3 102 NaN NaN ts
6 103 Aoi 23.0 ts
Upvotes: 1
Reputation: 862481
Use GroupBy.apply
with forward and back filling missing values ànd then set values by boolean mask:
cols = ['name','age']
df1 = df.groupby(['code'])[cols].apply(lambda x: x.ffill().bfill())
mask = df['char'] == 'ts'
df.loc[mask, cols] = df1.loc[mask, cols]
print (df)
code name age char
0 101 Carl 19.0 ts
1 101 NaN NaN tt
2 101 Carl 19.0 tt
3 102 NaN NaN ts
4 102 NaN NaN tt
5 102 NaN NaN tt
6 103 Aoi 23.0 ts
7 103 Aoi 23.0 tt
8 103 NaN NaN tt
Upvotes: 1