Pandas set values on iloc Nulls

Viewed 2680

I have a sample dataframe and function below. I created a function that will get the coordinates of a 'cell' and put that in a tuple, along with the reason why it was put there. I want this function to also change the value of a certain column.

import pandas as pd
import numpy as np
df1 = pd.DataFrame({'A' : [np.NaN,np.NaN,3,4,5,5,3,1,5,np.NaN], 
                    'B' : [1,0,3,5,0,0,np.NaN,9,0,0], 
                    'C' : [10,0,30,50,0,0,4,10,1,0], 
                    'D' : [1,0,3,4,0,0,7,8,0,1],
                    'E' : [np.nan,'Unassign','Assign','Ugly','Appreciate',
                          'Undo','Assign','Unicycle','Assign','Unicorn',]})
print(df1)
highlights = []
def find_nan(list_col):
    for c in list_col:
        # if column is one of the dataframe's columns, go
        if c in df1.columns:
            # for each index x where column c of the dataframe is null, go
            for x in df1.loc[df1[c].isnull()].index: #appends to the list of tuples
                highlights.append(
                    tuple([x + 2, df1.columns.get_loc(c) + 1, f'{c} is Null in row {x + 2}']))

                df1.iloc[x, df1.columns.get_loc('E')] = f'{c} is blank in row {x + 2}'
find_nan(['A','B']) 
    # using the function above, checks for all nulls in A and B
    # Also places the coordinates and reason in a tuple and changes values of column 'E'

    #output:
    A   B   C   D   E
0   NaN 1.0 10  1   A is blank in row 2
1   NaN 0.0 0   0   A is blank in row 3
2   3.0 3.0 30  3   Assign
3   4.0 5.0 50  4   Ugly
4   5.0 0.0 0   0   Appreciate
5   5.0 0.0 0   0   Undo
6   3.0 NaN 4   7   Assign
7   1.0 9.0 10  8   Unicycle
8   5.0 0.0 1   0   Assign
9   NaN 0.0 0   1   A is blank in row 11

What I want to do is add logic that will add the reasons together if E is already populated, or simply change the value of E if null. Here is my issue: using df1.iloc I cannot seem to check for nulls.

df1.iloc[0]['E'].isnull() returns AttributeError: 'float' object has no attribute 'isnull' (obviously)

to get around that: I can use if np.isnan(df1.iloc[0]['E']) which evaluates to True, but if there is a value already in E I will get a TypeError.

Essentially what I want is this sort of logic within my function:

if df1.iloc[x]['E'] is null:
    df1.iloc[x, df1.columns.get_loc('E')] = 'PREVIOUS_VALUE' + f'{c} is blank in row {x + 2}'
else:
    df1.iloc[x, df1.columns.get_loc('E')] = f'{c} is blank in row {x + 2}

Expected output from my function on the original dataframe:

find_nan(['A','B'])

    A   B   C   D   E
0   NaN 1.0 10  1   A is blank in row 2
1   NaN 0.0 0   0   Unassign and A is blank in row 3
2   3.0 3.0 30  3   Assign
3   4.0 5.0 50  4   Ugly
4   5.0 0.0 0   0   Appreciate
5   5.0 0.0 0   0   Undo
6   3.0 NaN 4   7   Assign and B is blank in row 8
7   1.0 9.0 10  8   Unicycle
8   5.0 0.0 1   0   Assign
9   NaN 0.0 0   1   Unicorn and A is blank in row 11

Using Python 3.6. this is part of a bigger project with more functions, hence the 'adding of reasons' and the adding of 2 to the index 'for no apparent reason'

2 Answers
Related