53

I have been struggling with this question for a long while, and I tried different methods.

I have a simple DataFrame as shown,

enter image description here

I can use code to replace NaN with None (Not String "None"),

[![dfTest2 = dfTest.where(pd.notnull(dfTest), None)][2]][2]

enter image description here

I support that NaT is also classified as 'Null' because the following, enter image description here

However, NaT is not replaced with None.

I have been searching for answers but got no luck. Anyone could Help?

Thank you in advance.

5
  • Any luck with df.fillna(None)? Commented Mar 15, 2017 at 18:50
  • @Cleb, tried but not won't work. Exception as ValueError: must specify a fill method or value. Seems that None is either an value or method. Commented Mar 15, 2017 at 18:52
  • This might be of help. Commented Mar 15, 2017 at 19:02
  • @Cleb Hi, Thx for the reference. Please see the answer below. Commented Mar 17, 2017 at 20:15
  • 1
    stackoverflow.com/a/42818550/8770481 This one saved my life. It worked well for me Commented Mar 26, 2020 at 8:57

11 Answers 11

52

Make the dtype object

dfTest2 = pd.DataFrame(dict(InvoiceDate=pd.to_datetime(['2017-06-01', pd.NaT])))

dfTest2.InvoiceDate.astype(object).where(dfTest2.InvoiceDate.notnull(), None)

0    2017-06-01 00:00:00
1                   None
Name: InvoiceDate, dtype: object
Sign up to request clarification or add additional context in comments.

4 Comments

Amazing!!! Thank you so so much. Totally make sense, the Timestamp type gives default NaT for Null. Thx again.
I don't wanna change the type of object and want it only in datetime format so this solution isn't working for me.
Your code gives me only the column affected as a result. But I want this to happen in in the DF itself and the original column replaced by this new one with None's. How to do that?
Assign the result back to the dataframe
36

The simplest solution I found that worked for me is...

Input:

import pandas as pd
import numpy as np
dfTest = pd.DataFrame(dict(InvoiceDate=pd.to_datetime(['2017-06-01', pd.NaT]), CorpId=[2997373, np.nan], TestName=[1,1]))
dfTest.replace({np.nan: None}, inplace = True)

Output of dfTest:

enter image description here

2 Comments

Note that pd.np was removed in Pandas 1.x.x
This also changes the column type to object
9

df.fillna(None) only works for np.na but not pd.NaT. However doing df.replace({np.nan: None}) replaces both pd.NaT and np.na with None.

# Initalize a sample dataframe
df = pd.DataFrame({
                    'start_date': pd.to_datetime(['2017-06-01', pd.NaT]), 
                    'amount':[2997373, np.nan]
                   })
display(df)

# Then replace pd.NaT and np.na with None
df = df.replace({np.nan: None})
display(df)

2 Comments

Thank you, this is the one that finally did it for me! Interestingly, df.replace(np.nan, None) has the same effect as df.fillna(None), but converting the replace call to a dict apparently makes all the difference.
I was mad why not working for me, I was using pandas version 1.4. Upgraded to 1.5 or latest it worked!
5

Make the column type as str first

 dfTest2.InvoiceDate =  dfTest2.InvoiceDate.astype(str)

then compare it directly with "NaT" and replace with None

dfTest2.InvoiceDate = dfTest2.InvoiceDate.apply(lambda x : None if x=="NaT" else x)

Comments

2

Similar approach as suggested by @neerajYadav but without the apply:

dfTest2['InvoiceDate'] = (dfTest2['InvoiceDate']
                          .astype(str) # <- cast to string to simplify
                                       #    .replace() in newer versions
                          .replace({'NaT': None} # <- replace with None
                         )

1 Comment

This will change the column type to str, which in some cases we don't want that to happen
2

So I'm a little late to the party, but this result also worked for me.

`

import pandas as pd

df["column"] = df["column"].replace({pd.NaT: None})

`

Comments

0

This looks strange but worked for me. Pandas version 14.1

import numpy as np

df = df.replace(np.NaN, 0).replace(0, None)

Before LastModifiedDate NaT

After LastModifiedDate None

1 Comment

This cannot be correct. When to_replace= is a scalar and value= is None (as in your second .replace() call above), the function uses the method= parameter (see docs and this Github issue comment), which means forward-filling last non-null (and non-0 in your case).
0

I see a couple of other similar answers here, though none are as simple as this:

df.replace([pd.NaT], [None])

Comments

0

dfTest2.replace({pd.NaT:None},inplace=True)

Comments

0

df = df.astype(object).mask(df.isna(), None)

Comments

-1

If you don't want to change the type of the column, then another alternative is to to replace all missing values (pd.NaT) first with np.nan and then replace the latter with None:

import numpy as np

df = df.fillna(np.nan).replace([np.nan], [None])

2 Comments

df.fillna(np.nan) does not replace NaT with nan.
why not just df.replace([pd.NaT], [None])

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.