【问题标题】:How to interpolate only between values (stopping before and after last NaN in a column) with pandas?如何使用熊猫仅在值之间进行插值(在一列中最后一个 NaN 之前和之后停止)?
【发布时间】:2018-05-17 16:06:32
【问题描述】:

如果我有一个类似于这个的df

print(df)
                       A  B  C    D    E
 DATE_TIME                               
2016-08-10 13:57:00  3.6  A  1  NaN  NaN
2016-08-10 13:58:00  4.7  A  1  4.5  NaN
2016-08-10 13:59:00  3.4  A  0  NaN  5.7
2016-08-10 14:00:00  3.5  A  0  NaN  NaN
2016-08-10 14:01:00  2.6  A  0  4.6  NaN
2016-08-10 14:02:00  4.8  A  0  NaN  4.3
2016-08-10 14:03:00  5.7  A  1  NaN  NaN
2016-08-10 14:04:00  5.5  A  1  5.7  NaN
2016-08-10 14:05:00  5.6  A  1  NaN  NaN
2016-08-10 14:06:00  7.8  A  1  NaN  5.2
2016-08-10 14:07:00  8.9  A  0  NaN  NaN
2016-08-10 14:08:00  3.6  A  0  NaN  NaN

print (df.dtypes)
A    float64
B     object
C      int64
D    float64
E    float64
dtype: object

感谢社区的大量输入,我现在有了这段代码,它允许我将我的 df 上采样到秒间隔,对不同的dtypes 应用不同的方法

int_cols = df.select_dtypes(['int64']).columns
index = pd.date_range(df.index[0], df.index[-1], freq="s")
df2 = df.reindex(index)

for col in df2:
if col == int_cols.all(): 
    df2[col].ffill(inplace=True)
    df2[col] = df2[col].astype(int)
elif df2[col].dtype == float:
    df2[col].interpolate(inplace=True)
else:
    df2[col].ffill(inplace=True)

我现在正在寻找一种方法,只在我的实际测量值之间进行插值。 interpolate 函数将我的最后一次测量延长到df 结束:

 df2.tail()
Out[75]: 
                            A  B  C    D    E
2016-08-10 14:07:56  3.953333  A  0  5.7  5.2
2016-08-10 14:07:57  3.865000  A  0  5.7  5.2
2016-08-10 14:07:58  3.776667  A  0  5.7  5.2
2016-08-10 14:07:59  3.688333  A  0  5.7  5.2
2016-08-10 14:08:00  3.600000  A  0  5.7  5.2

但我想在最后一次测量发生时停止此操作(例如在 14:04:00 col['D'] 和 14:06:00 col['D'])并留下 NaN。

它尝试将“limit”和“limit_direction”的零值添加到“both”:

 for col in df2:
if col == int_cols.all(): 
    df2[col].ffill(inplace=True)
    df2[col] = df2[col].astype(int)
elif df2[col].dtype == float:
    df2[col].interpolate(inplace=True,limit=0, limit_direction='both')
else:
    df2[col].ffill(inplace=True)

但这并没有改变任何输出。我试图将我找到的解决方案合并到这个问题:Pandas: interpolation where first and last data point in column is NaN 到我的代码中:

for col in df2:
if col == int_cols.all(): 
    df2[col].ffill(inplace=True)
    df2[col] = df2[col].astype(int)
elif df2[col].dtype == float:
   df2[col].loc[df2[col].first_valid_index(): df2[col].last_valid_index()]=df2[col].loc[df2[col].first_valid_index(): df2[col].last_valid_index()].astype(float).interpolate(inplace=True)
else:
    df2[col].ffill(inplace=True)

...但这不起作用,我的float64 列现在纯粹是 NaN...另外,我尝试插入代码的方式,我知道它只会影响float 列。在一个理想的解决方案中,我希望将此first_valid_index():.last_valid_index() 选择也设置为objectint64 列。有人可以帮助我吗? ..谢谢你

【问题讨论】:

    标签: python pandas interpolation


    【解决方案1】:

    对于熊猫0.23.0,可以在interpolate 中使用参数limit_area

    df = pd.DataFrame({'A': [np.nan, 1.0, np.nan, np.nan, 4.0, np.nan, np.nan],
                       'B': [np.nan, np.nan, 0.0, np.nan, np.nan, 2.0, np.nan]},
                      columns=['A', 'B'], 
                      index=pd.date_range(start='2016-08-10 13:50:00', periods=7, freq='S'))
    print (df)
                           A    B
    2016-08-10 13:50:00  NaN  NaN
    2016-08-10 13:50:01  1.0  NaN
    2016-08-10 13:50:02  NaN  0.0
    2016-08-10 13:50:03  NaN  NaN
    2016-08-10 13:50:04  4.0  NaN
    2016-08-10 13:50:05  NaN  2.0
    2016-08-10 13:50:06  NaN  NaN
    
    df = df.interpolate(limit_direction='both', limit_area='inside')
    print (df)
                           A         B
    2016-08-10 13:50:00  NaN       NaN
    2016-08-10 13:50:01  1.0       NaN
    2016-08-10 13:50:02  2.0  0.000000
    2016-08-10 13:50:03  3.0  0.666667
    2016-08-10 13:50:04  4.0  1.333333
    2016-08-10 13:50:05  NaN  2.000000
    2016-08-10 13:50:06  NaN       NaN
    

    【讨论】:

      【解决方案2】:

      你很亲密!这是一个与您在帖子末尾发布的代码非常相似的示例:

      import numpy as np
      import pandas as pd
      
      df = pd.DataFrame({'A': [np.nan, 1.0, np.nan, np.nan, 4.0, np.nan, np.nan],
                         'B': [np.nan, np.nan, 0.0, np.nan, np.nan, 2.0, np.nan]},
                        columns=['A', 'B'], 
                        index=pd.date_range(start='2016-08-10 13:50:00', periods=7, freq='S'))
      print df
      
      A_first = df['A'].first_valid_index()
      A_last = df['A'].last_valid_index()
      df.loc[A_first:A_last, 'A'] = df.loc[A_first:A_last, 'A'].interpolate()
      
      B_first = df['B'].first_valid_index()
      B_last = df['B'].last_valid_index()
      df.loc[B_first:B_last, 'B'] = df.loc[B_first:B_last, 'B'].interpolate()
      
      print df
      

      结果:

                             A    B
      2016-08-10 13:50:00  NaN  NaN
      2016-08-10 13:50:01  1.0  NaN
      2016-08-10 13:50:02  NaN  0.0
      2016-08-10 13:50:03  NaN  NaN
      2016-08-10 13:50:04  4.0  NaN
      2016-08-10 13:50:05  NaN  2.0
      2016-08-10 13:50:06  NaN  NaN
      
                             A         B
      2016-08-10 13:50:00  NaN       NaN
      2016-08-10 13:50:01  1.0       NaN
      2016-08-10 13:50:02  2.0  0.000000
      2016-08-10 13:50:03  3.0  0.666667
      2016-08-10 13:50:04  4.0  1.333333
      2016-08-10 13:50:05  NaN  2.000000
      2016-08-10 13:50:06  NaN       NaN
      

      您的代码中的两个问题是:

      1. 如果你要做df[...] = df[...].interpolate(),你需要 删除inplace=True,因为这将使它返回None。这是你的主要问题,也是你得到所有NaNs 的原因。
      2. 虽然它似乎在这里工作,但一般来说,链式索引是不好的:

      你想要:

      df.loc[A_first:A_last, 'A'] = df.loc[A_first:A_last, 'A'].interpolate()
      

      不是:

      df['A'].loc[A_first:A_last] = df['A'].loc[A_first:A_last].interpolate()
      

      更多详情请看这里:http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

      【讨论】:

      • 非常感谢您的解释和有用的链接。我尝试使用您的df 跟随df.loc[df['A'].first_valid_index():df['A'].last_valid_index()] = df.loc[df['A'].first_valid_index():df['A'].last_valid_index()].interpolate() 行,看看它会做什么,我很惊讶B 列也发生了变化。为什么会这样?我还更改了代码中的行:df2.loc[df2[col].first_valid_index():df2[col].last_valid_index()] = df2.loc[df[col].first_valid_index():df2[col].last_valid_index()].interpolate(),但仍然无法正常工作。抱歉又问了,我真的很想学习
      • 它也在改变 B 列,因为你没有指定一列,所以它对每一列进行插值。通常,您需要的是df.loc[<slice of rows>, <column>] = df.loc[<slice of rows>, <column>]。具体来说,您需要的是df.loc[df['A'].first_valid_index():df['A'].last_valid_index(‌​), 'A'] = df.loc[df['A'].first_valid_index():df['A'].last_valid_index(‌​), 'A'].interpolate()df2.loc[df2[col].first_valid_index():df2[col].last_valid_ind‌​ex(), col] = df2.loc[df[col].first_valid_index():df2[col].last_valid_inde‌​x(), col].interpolate()
      • 谢谢!它现在正在工作!不过,我很困惑,当我运行这一行时(我在原始答案中修改了这一行)df.loc[df['A'].first_valid_index():df['A'].last_valid_index(), 'A'] = df.loc[df['A'].first_valid_index():df['A'].last_valid_index(), 'A'].interpolate() 它可以工作,但是这条看似完全相同的行df.loc[df['A'].first_valid_index():df['A'].last_valid_index(‌​‌​), 'A'] = df.loc[df['A'].first_valid_index():df['A'].last_valid_index(‌​‌​), 'A'].interpolate() 作为您上次编辑的复制过去,我得到了@ 987654339@我疯了吗?
      • 奇怪,在复制和粘贴的过程中可能有一些看不见的字符进入了那里? stackoverflow.com/a/14844830/5405967
      • 确实....我复制到记事本中,这是last_valid_index(??) vs. last_valid_index(??????)....非常感谢!
      【解决方案3】:

      您可以回填空值,然后使用布尔索引获取每列的空值(必须是尾部空值)。

      for col in ['D', 'E']:
          idx = df[df[col].bfill().isnull()].index
          df[col].ffill(inplace=True)
          df.loc[idx, col] = None
      

      【讨论】:

      • 谢谢!我仍在尝试了解如何使用它!我明白我认为应该怎么做,但我还没有到那里..
      猜你喜欢
      • 2020-04-10
      • 1970-01-01
      • 1970-01-01
      • 2015-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多