【发布时间】:2019-05-14 10:11:44
【问题描述】:
我有一些不同长度的数字时间序列存储在一个宽大的熊猫数据框中。每行对应一个系列,每列对应一个测量时间点。由于它们的长度不同,这些序列可能在左侧(第一个时间点)或右侧(最后一个时间点)或两者都有缺失值 (NA) 尾部。每行总是有一个没有最小长度的 NA 的连续条带。
我需要从这些行中的每一行中获取一个固定长度的随机子集,而不包括任何 NA。理想情况下,我希望保持原始数据帧完整,并在新数据帧中报告子集。
我设法通过一个效率非常低的 for 循环获得此输出,该循环逐行遍历每一行,确定裁剪位置的开始,以便 NA 不会包含在输出中并复制裁剪结果。这可行,但在大型数据集上非常慢。代码如下:
import pandas as pd
import numpy as np
from copy import copy
def crop_random(df_in, output_length, ignore_na_tails=True):
# Initialize new dataframe
colnames = ['X_' + str(i) for i in range(output_length)]
df_crop = pd.DataFrame(index=df_in.index, columns=colnames)
# Go through all rows
for irow in range(df_in.shape[0]):
series = copy(df_in.iloc[irow, :])
series = np.array(series).astype('float')
length = len(series)
if ignore_na_tails:
pos_non_na = np.where(~np.isnan(series))
# Range where the subset might start
lo = pos_non_na[0][0]
hi = pos_non_na[0][-1]
left = np.random.randint(lo, hi - output_length + 2)
else:
left = np.random.randint(0, length - output_length)
series = series[left : left + output_length]
df_crop.iloc[irow, :] = series
return df_crop
还有一个玩具例子:
df = pd.DataFrame.from_dict({'t0': [np.NaN, 1, np.NaN],
't1': [np.NaN, 2, np.NaN],
't2': [np.NaN, 3, np.NaN],
't3': [1, 4, 1],
't4': [2, 5, 2],
't5': [3, 6, 3],
't6': [4, 7, np.NaN],
't7': [5, 8, np.NaN],
't8': [6, 9, np.NaN]})
# t0 t1 t2 t3 t4 t5 t6 t7 t8
# 0 NaN NaN NaN 1 2 3 4 5 6
# 1 1 2 3 4 5 6 7 8 9
# 2 NaN NaN NaN 1 2 3 NaN NaN NaN
crop_random(df, 3)
# One possible output:
# X_0 X_1 X_2
# 0 2 3 4
# 1 7 8 9
# 2 1 2 3
我怎样才能以适应大型数据框的方式获得相同的结果?
编辑:将我改进的解决方案移至答案部分。
【问题讨论】: