大熊猫用最接近的非数字值进行插值

API*_*API 6 datetime python-3.x pandas

我有一个带有日期时间索引的数字和非数字值的数据框:

df = pd.DataFrame([
    {'date': datetime(2017, 4, 24, 1), 'a':1, 'b':2, 'c': "hee"},
    {'date': datetime(2017, 4, 24, 2), 'a':2, 'b':4, 'c': 'hoo'},
    {'date': datetime(2017, 4, 24, 3), 'a':4, 'b':8, 'c': 'joo'},
    {'date': datetime(2017, 4, 24, 4), 'a':8, 'b':16, 'c': 'jee'}
]).set_index('date')
Run Code Online (Sandbox Code Playgroud)

我想要:

  • 线性插值数值;和
  • 获取非数字值的最接近值。

什么是最优雅的实现?

策略一

插入所有,然后fillna

df = df.resample('20T').interpolate('linear')
df.fillna(method='nearest')
Run Code Online (Sandbox Code Playgroud)

但是……该nearest方法没有实现。

策略二

拆分数字和非数字列

df2 = df.resample('20T')
df_a = df2._get_numeric_data().interpolate('linear')
df_b = df2[list(set(df.columns) - set(set(df_a.columns)))].interpolate('nearest')
Run Code Online (Sandbox Code Playgroud)

这给出了一个错误:

类型错误:无法插入所有 NaN。

更新

使用最近方法进行插值确实适用于布尔值和数值,但不适用于字符串,例如:

df.resample('20T').intepolate('nearest')
Run Code Online (Sandbox Code Playgroud)

小智 3

由于interpolate("nearest")数字类型可以正常工作,因此解决方案是:

  1. 将列从字符串转换为分类(数字)
  2. 插入分类interpolate("nearest")
  3. 将插值的分类列映射回字符串

    def fillna_nearest(series):
        fact = series.astype('category').factorize()
    
        series_cat = pd.Series(fact[0]).replace(-1, np.nan) # get string as categorical (-1 is NaN)
        series_cat_interp = series_cat.interpolate("nearest") # interpolate categorical
    
        cat_to_string = {i:x for i,x in enumerate(fact[1])} # dict connecting category to string
        series_str_interp = series_cat_interp.map(cat_to_string) # turn category back to string
    
        return series_str_interp
    
    
    In [10]: df.resample('20T').interpolate().apply(fillna_nearest)
    Out[10]: 
              a          b    c
    0  1.000000   2.000000  hee
    1  1.333333   2.666667  hee
    2  1.666667   3.333333  hoo
    3  2.000000   4.000000  hoo
    4  2.666667   5.333333  hoo
    5  3.333333   6.666667  joo
    6  4.000000   8.000000  joo
    7  5.333333  10.666667  joo
    8  6.666667  13.333333  jee
    9  8.000000  16.000000  jee
    
    Run Code Online (Sandbox Code Playgroud)