向此 Dataframe 添加部分行时,为什么我得到的是 NaT 值而不是 NaN?
Why do I get NaT values rather than NaN when adding partial rows to this Dataframe?
我有一个脚本可以将 .csv 文件读入数据框,然后允许用户通过向其中添加额外数据来扩展数据框。它将采用 date
列中的最后一个值,并开始每天提示用户输入一个值。
如果用户没有为 input
指定任何内容,那么该值将被转换为 math.nan
。除了当我将该行附加到数据框时,假设的 NaN
被转换为 NaT
.
我在下面重新创建了一个可重现的示例。
如何确保我的 NaN
不会转换为 NaT
?
#!/usr/bin/env python
import pandas as pd
import datetime as dt
import math
df = pd.DataFrame({
'date': pd.to_datetime(['2022-05-01', '2022-05-02', '2022-05-03']),
'weight': [250., 249, 247],
})
last_recorded_date = df['date'].iloc[-1]
next_date = last_recorded_date + dt.timedelta(days=1)
df.loc[len(df.index)] = [next_date, math.nan]
print(df)
# date weight
# 0 2022-05-01 250.0
# 1 2022-05-02 249.0
# 2 2022-05-03 247.0
# 3 2022-05-06 NaT
import pandas as pd
import datetime as dt
import math
df = pd.DataFrame({
'date': pd.to_datetime(['2022-05-01', '2022-05-02', '2022-05-03']),
'weight': [250., 249, 247],
})
last_recorded_date = df['date'].iloc[-1]
while True:
next_date = last_recorded_date + dt.timedelta(days=1)
weight = input(f"{next_date}: ")
if weight == 'q':
break
elif weight == '':
weight = math.nan
else:
weight = float(weight)
df.loc[len(df.index)] = [next_date, weight]
last_recorded_date = next_date
df = df['weight'].replace(pd.NaT, math.nan)
print(df)
这很奇怪。但一些实验揭示了一些线索:
df = pd.DataFrame({
'date': pd.to_datetime(['2022-05-01', '2022-05-02', '2022-05-03']),
'weight': [250., 249, 247],
})
# Try this
df.loc[4] = None
加薪:
FutureWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.
这并不能完全解释为什么将 NaT
添加到第二列,但它确实表明在附加到现有数据帧时需要指定类型。
如here所述,一种解决方案如下:
df = pd.DataFrame({
'date': pd.to_datetime(['2022-05-01', '2022-05-02', '2022-05-03']),
'weight': [250., 249, 247],
})
next_date = pd.Timestamp('2022-05-04')
df = df.append(pd.DataFrame([{'date': next_date, 'weight': np.nan}]), ignore_index=True)
assert (df.dtypes.values == ('<M8[ns]', 'float64')).all()
然而,这引发了:
FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
df = df.append(pd.DataFrame([{'date': next_date, 'weight': np.nan}]), ignore_index=True)
所以我想现在正确的解决方案是:
new_row = pd.DataFrame([{'date': next_date, 'weight': np.nan}])
df = pd.concat([df, new_row]).reset_index(drop=True)
assert (df.dtypes.values == ('<M8[ns]', 'float64')).all()
但我必须问,为什么要以这种方式附加到数据框?这是非常低效的,应该尽可能避免。
从 list
设置行时,列表首先转换为 Series
。 Series
的元素必须是同一类型;第一个值是 datetime
;因此每个值都在结果 Series
中转换为 datetime
。特别是,math.nan
变为 NaT
。 Pandas不使用现有的列类型来通知进程;相反,列类型会根据需要进行调整 - weight
列的类型从 float
扩展为 object
.
根据我的测试,使用元组似乎可以解决问题:
df.loc[len(df.index)] = (next_date, math.nan)
我有一个脚本可以将 .csv 文件读入数据框,然后允许用户通过向其中添加额外数据来扩展数据框。它将采用 date
列中的最后一个值,并开始每天提示用户输入一个值。
如果用户没有为 input
指定任何内容,那么该值将被转换为 math.nan
。除了当我将该行附加到数据框时,假设的 NaN
被转换为 NaT
.
我在下面重新创建了一个可重现的示例。
如何确保我的 NaN
不会转换为 NaT
?
#!/usr/bin/env python
import pandas as pd
import datetime as dt
import math
df = pd.DataFrame({
'date': pd.to_datetime(['2022-05-01', '2022-05-02', '2022-05-03']),
'weight': [250., 249, 247],
})
last_recorded_date = df['date'].iloc[-1]
next_date = last_recorded_date + dt.timedelta(days=1)
df.loc[len(df.index)] = [next_date, math.nan]
print(df)
# date weight
# 0 2022-05-01 250.0
# 1 2022-05-02 249.0
# 2 2022-05-03 247.0
# 3 2022-05-06 NaT
import pandas as pd
import datetime as dt
import math
df = pd.DataFrame({
'date': pd.to_datetime(['2022-05-01', '2022-05-02', '2022-05-03']),
'weight': [250., 249, 247],
})
last_recorded_date = df['date'].iloc[-1]
while True:
next_date = last_recorded_date + dt.timedelta(days=1)
weight = input(f"{next_date}: ")
if weight == 'q':
break
elif weight == '':
weight = math.nan
else:
weight = float(weight)
df.loc[len(df.index)] = [next_date, weight]
last_recorded_date = next_date
df = df['weight'].replace(pd.NaT, math.nan)
print(df)
这很奇怪。但一些实验揭示了一些线索:
df = pd.DataFrame({
'date': pd.to_datetime(['2022-05-01', '2022-05-02', '2022-05-03']),
'weight': [250., 249, 247],
})
# Try this
df.loc[4] = None
加薪:
FutureWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.
这并不能完全解释为什么将 NaT
添加到第二列,但它确实表明在附加到现有数据帧时需要指定类型。
如here所述,一种解决方案如下:
df = pd.DataFrame({
'date': pd.to_datetime(['2022-05-01', '2022-05-02', '2022-05-03']),
'weight': [250., 249, 247],
})
next_date = pd.Timestamp('2022-05-04')
df = df.append(pd.DataFrame([{'date': next_date, 'weight': np.nan}]), ignore_index=True)
assert (df.dtypes.values == ('<M8[ns]', 'float64')).all()
然而,这引发了:
FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
df = df.append(pd.DataFrame([{'date': next_date, 'weight': np.nan}]), ignore_index=True)
所以我想现在正确的解决方案是:
new_row = pd.DataFrame([{'date': next_date, 'weight': np.nan}])
df = pd.concat([df, new_row]).reset_index(drop=True)
assert (df.dtypes.values == ('<M8[ns]', 'float64')).all()
但我必须问,为什么要以这种方式附加到数据框?这是非常低效的,应该尽可能避免。
从 list
设置行时,列表首先转换为 Series
。 Series
的元素必须是同一类型;第一个值是 datetime
;因此每个值都在结果 Series
中转换为 datetime
。特别是,math.nan
变为 NaT
。 Pandas不使用现有的列类型来通知进程;相反,列类型会根据需要进行调整 - weight
列的类型从 float
扩展为 object
.
根据我的测试,使用元组似乎可以解决问题:
df.loc[len(df.index)] = (next_date, math.nan)