I have a dataframe of shape (40,500). Each row in the dataframe has some numerical values till some variable column number k, and all the entries after that are nan.
I am trying to get the value of last non-nan column in each row. Is there a way to do this without looping through all the rows of the dataframe?
Sample Dataframe:
2016-06-02 7.080 7.079 7.079 7.079 7.079 7.079 nan nan nan
2016-06-08 7.053 7.053 7.053 7.053 7.053 7.054 nan nan nan
2016-06-09 7.061 7.061 7.060 7.060 7.060 7.060 nan nan nan
2016-06-14 nan nan nan nan nan nan nan nan nan
2016-06-15 7.066 7.066 7.066 7.066 nan nan nan nan nan
2016-06-16 7.067 7.067 7.067 7.067 7.067 7.067 7.068 7.068 nan
2016-06-21 7.053 7.053 7.052 nan nan nan nan nan nan
2016-06-22 7.049 7.049 nan nan nan nan nan nan nan
2016-06-28 7.058 7.058 7.059 7.059 7.059 7.059 7.059 7.059 7.059
Reqd output
2016-06-02 7.079
2016-06-08 7.054
2016-06-09 7.060
2016-06-14 nan
2016-06-15 7.066
2016-06-16 7.068
2016-06-21 7.052
2016-06-22 7.049
2016-06-28 7.059
You need last_valid_index
with custom function, because if all values are NaN
it return KeyError
:
def f(x):
if x.last_valid_index() is None:
return np.nan
else:
return x[x.last_valid_index()]
df['status'] = df.apply(f, axis=1)
print (df)
1 2 3 4 5 6 7 8 9 \
0
2016-06-02 7.080 7.079 7.079 7.079 7.079 7.079 NaN NaN NaN
2016-06-08 7.053 7.053 7.053 7.053 7.053 7.054 NaN NaN NaN
2016-06-09 7.061 7.061 7.060 7.060 7.060 7.060 NaN NaN NaN
2016-06-14 NaN NaN NaN NaN NaN NaN NaN NaN NaN
2016-06-15 7.066 7.066 7.066 7.066 NaN NaN NaN NaN NaN
2016-06-16 7.067 7.067 7.067 7.067 7.067 7.067 7.068 7.068 NaN
2016-06-21 7.053 7.053 7.052 NaN NaN NaN NaN NaN NaN
2016-06-22 7.049 7.049 NaN NaN NaN NaN NaN NaN NaN
2016-06-28 7.058 7.058 7.059 7.059 7.059 7.059 7.059 7.059 7.059
status
0
2016-06-02 7.079
2016-06-08 7.054
2016-06-09 7.060
2016-06-14 NaN
2016-06-15 7.066
2016-06-16 7.068
2016-06-21 7.052
2016-06-22 7.049
2016-06-28 7.059
Alternative solution - fillna
with method ffill
and select last column by iloc
:
df['status'] = df.ffill(axis=1).iloc[:, -1]
print (df)
status
0
2016-06-02 7.079
2016-06-08 7.054
2016-06-09 7.060
2016-06-14 NaN
2016-06-15 7.066
2016-06-16 7.068
2016-06-21 7.052
2016-06-22 7.049
2016-06-28 7.059
use agg('last')
df.groupby(['status'] * df.shape[1], 1).agg('last')
'last' within agg produces that last valid value within group. I passed a list of length equal to the number of columns. Each value of this list is 'status'. That means that I'm grouping by one group. The result is a dataframe with one column named 'status'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With