我遇到了完全相同的问题,导致我进入此页面。对于这个问题,我没有真正好的解决方案,我自己也在寻找一个……但我确实找到了解决方法。在进入之前,我想回答在原始问题上发表的评论:允许将NA 甚至None 值分配给int8 这样的“简单”类型系列是尝试的重点进行这些 dtype 转换。可以对一系列这些 dtype 执行典型操作,例如 isna() (等等)(请参阅 pd.IntXDtype() where 'X'代表位数)。我通过使用这些 dtypes 探索的优势在于内存占用,例如:
In[56]: test_df = pd.Series(np.zeros(1_000_000), dtype=np.float64)
In[57]: test_df.memory_usage()
Out[57]: 8000128
In[58]: test_df = pd.Series(np.zeros(1_000_000), dtype=pd.Int8Dtype())
In[59]: test_df.memory_usage()
Out[59]: 2000128
In[60]: test_df.iloc[:500_000] = None
In[61]: test_df.memory_usage()
Out[61]: 2000128
In[62]: test_df.isna().sum()
Out[62]: 500000
这样你就可以两全其美了。
现在解决方法:
In[33]: my_df
Out[33]:
a s d
0 0 -500 -1.000
1 1 -499 -0.998
2 2 -498 -0.996
3 3 -497 -0.994
4 4 -496 -0.992
In[34]: my_df.dtypes
Out[34]:
a int64
s int64
d float64
dtype: object
In[35]: df_converted_to_int_first = my_df.astype(
...: dtype={
...: 'a': np.int8,
...: 's': np.int16,
...: 'd': np.float16,
...: },
...: )
In[36]: df_converted_to_int_first
Out[36]:
a s d
0 0 -500 -1.000000
1 1 -499 -0.998047
2 2 -498 -0.996094
3 3 -497 -0.994141
4 4 -496 -0.992188
In[37]: df_converted_to_int_first.dtypes
Out[37]:
a int8
s int16
d float16
dtype: object
In[38]: df_converted_to_special_int_after = df_converted_to_int_first.astype(
...: dtype={
...: 'a': pd.Int8Dtype(),
...: 's': pd.Int16Dtype(),
...: }
...: )
In[39]: df_converted_to_special_int_after.dtypes
Out[39]:
a Int8
s Int16
d float16
dtype: object
In[40]: df_converted_to_special_int_after.a.iloc[3] = None
In[41]: df_converted_to_special_int_after
Out[41]:
a s d
0 0 -500 -1.000000
1 1 -499 -0.998047
2 2 -498 -0.996094
3 <NA> -497 -0.994141
4 4 -496 -0.992188
在我看来,这仍然不是一个可接受的解决方案......但如上所述,ir 构成了原始问题中提出的解决方法。
编辑
缺少一些测试,从 np.float64 到 pd.Int8Dtype():
In[67]: my_df.astype(
...: dtype={
...: 'a': np.int8,
...: 's': np.int16,
...: 'd': np.int16,
...: },
...: ).astype(
...: dtype={
...: 'a': np.int8,
...: 's': np.int16,
...: 'd': pd.Int8Dtype(),
...: },
...: ).dtypes
Out[67]:
a int8
s int16
d Int8
dtype: object