首页 > 解决方案 > Pandas 在数据帧的每一列的第一个有效索引之前和最后一个有效索引之后下降

问题描述

我有一个这样的数据框:

df = pd.DataFrame({'timestamp':pd.date_range('2018-01-01', '2018-01-02', freq='2h', closed='right'),'col1':[np.nan, np.nan, np.nan, 1,2,3,4,5,6,7,8,np.nan], 'col2':[np.nan, np.nan, 0, 1,2,3,4,5,np.nan,np.nan,np.nan,np.nan], 'col3':[np.nan, -1, 0, 1,2,3,4,5,6,7,8,9], 'col4':[-2, -1, 0, 1,2,3,4,np.nan,np.nan,np.nan,np.nan,np.nan]
              })[['timestamp', 'col1', 'col2', 'col3', 'col4']]

看起来像这样:

             timestamp  col1  col2  col3  col4
0  2018-01-01 02:00:00   NaN   NaN   NaN  -2.0
1  2018-01-01 04:00:00   NaN   NaN  -1.0  -1.0
2  2018-01-01 06:00:00   NaN   0.0   NaN   0.0
3  2018-01-01 08:00:00   1.0   1.0   1.0   1.0
4  2018-01-01 10:00:00   2.0   NaN   2.0   2.0
5  2018-01-01 12:00:00   3.0   3.0   NaN   3.0
6  2018-01-01 14:00:00   NaN   4.0   4.0   4.0
7  2018-01-01 16:00:00   5.0   NaN   5.0   NaN
8  2018-01-01 18:00:00   6.0   NaN   6.0   NaN
9  2018-01-01 20:00:00   7.0   NaN   7.0   NaN
10 2018-01-01 22:00:00   8.0   NaN   8.0   NaN
11 2018-01-02 00:00:00   NaN   NaN   9.0   NaN

现在,我想在第一个有效索引之前和最后一个有效索引之后找到一种有效且 Pythonic 的切断方式(对于每一列!不计算时间戳)。在这个例子中,我有 4 列,但实际上我有更多,大约 600 列。我正在寻找一种对第一个有效索引之前的所有 NaN 值和最后一个有效索引之后的所有 NaN 值进行切割的方法。

我猜一种方法是循环遍历..但是有更好的方法吗?这种方式必须是有效的。我尝试使用熔化“取消旋转”数据框,但这并没有帮助。

很明显的一点是,每列在切割后会有不同的行数。因此,我希望结果是具有时间戳和相关列的数据帧列表(每列一个)。例如:

             timestamp  col1   
3  2018-01-01 08:00:00   1.0  
4  2018-01-01 10:00:00   2.0   
5  2018-01-01 12:00:00   3.0   
6  2018-01-01 14:00:00   NaN   
7  2018-01-01 16:00:00   5.0   
8  2018-01-01 18:00:00   6.0   
9  2018-01-01 20:00:00   7.0   
10 2018-01-01 22:00:00   8.0    

我的尝试

我试过这样:

final = []
columns = [c for c in df if c !='timestamp']
for col in columns:
    first = df.loc[:, col].first_valid_index()
    last = df.loc[:, col].last_valid_index()
    final.append(df.loc[:, ['timestamp', col]].iloc[first:last+1, :])

标签: pythonpandas

解决方案


您可以使用函数式编程的强大功能并将函数应用于每一列。这可能会加快速度。此外,当您timestamps看起来排序时,您可以将它们用作 Datarame 的索引。

df.set_index('timestamp', inplace=True)

final = []
def func(col):
    first = col.first_valid_index()
    last = col.last_valid_index()
    final.append(col.loc[first:last])
    return

df.apply(func)

此外,您可以将所有内容压缩在一个衬里中:

final = []
df.apply(lambda col: final.append(col.loc[col.first_valid_index() : col.last_valid_index()]))

推荐阅读