0

I have a dataframe that contains some NaN-values in a t-column. The values in the t-column belong to a certain id and should be the same per id:

df = pd.DataFrame({"t"  :   [4, 4, 1, 1, float('nan'), 2, 2, 2, float('nan'), 10],
                   "id":    [1, 1, 2, 2, 3, 3, 3 , 3, 4, 4]})

Therefore, I would like to overwrite the NaN in t with the non-NaN in t for the respective id and ultimately end up with

df = pd.DataFrame({"t"  :   [4, 4, 1, 1, 2, 2, 2, 2, 10, 10],
                   "id":    [1, 1, 2, 2, 3, 3, 3 , 3, 4, 4]})
N08
  • 1,265
  • 13
  • 23
  • similar to this [link](https://stackoverflow.com/questions/27905295/how-to-replace-nans-by-preceding-values-in-pandas-dataframe) ? – gyx-hh Mar 21 '18 at 10:59
  • @HamzaHaider No, not quite. If you read my OP, then my example is based on an `id` that we use to identify the correct `t` to use - it is not necessarily based preceding values – N08 Mar 21 '18 at 11:01

2 Answers2

5

New strategy... Create a map by dropping na and reassign using loc and mask.

import pandas as pd

df = pd.DataFrame({"t"  :   [4, 4, 1, 1, float('nan'), 2, 2, 2, float('nan'), 10],
                   "id":    [1, 1, 2, 2, 3, 3, 3 , 3, 4, 4]})

# create mask
m = pd.isna(df['t'])

# create map
#d = df[~m].set_index('id')['t'].drop_duplicates()
d = df[~m].set_index('id')['t'].to_dict()

# assign map to the slice of the dataframe containing nan
df.loc[m,'t'] = df.loc[m,'id'].map(d)

print(df)

df returns:

   id     t
0   1   4.0
1   1   4.0
2   2   1.0
3   2   1.0
4   3   2.0
5   3   2.0
6   3   2.0
7   3   2.0
8   4  10.0
9   4  10.0
Anton vBR
  • 18,287
  • 5
  • 40
  • 46
2

Use sort_values with groupby and transform for same column with first:

df['t'] = df.sort_values(['id','t']).groupby('id')['t'].transform('first')

Alternative solution is map by Series created by dropna with drop_duplicates:

df['t'] = df['id'].map(df.dropna(subset=['t']).drop_duplicates('id').set_index('id')['t'])

print (df)
   id     t
0   1   4.0
1   1   4.0
2   2   1.0
3   2   1.0
4   3   2.0
5   3   2.0
6   3   2.0
7   3   2.0
8   4  10.0
9   4  10.0
jezrael
  • 822,522
  • 95
  • 1,334
  • 1,252