首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Pandas:从受限列范围内的每一行中获取随机子集的有效方法

Pandas:从受限列范围内的每一行中获取随机子集的有效方法
EN

Stack Overflow用户
提问于 2019-05-14 18:11:44
回答 1查看 52关注 0票数 2

我有一些不同长度的数值时间序列存储在一个广泛的熊猫数据帧中。每行对应一个序列,每列对应一个测量时间点。由于它们的长度不同,这些序列可能会有缺失值(NA)尾部,或者是左侧(第一个时间点)或右侧(最后一个时间点),或者两者都有。每行上总是有一个连续的条带,没有最小长度的NA。

我需要从这些行中的每一行中获取固定长度的随机子集,而不包括任何NA。理想情况下,我希望保持原始数据帧完好无损,并在新的数据帧中报告子集。

我设法通过一个非常低效的for循环获得了这个输出,该循环逐一遍历每一行,确定裁剪位置的开始,使得NAs不会包含在输出中,并复制裁剪的结果。这是可行的,但在大型数据集上速度非常慢。代码如下:

代码语言:javascript
运行
复制
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

还有一个玩具的例子:

代码语言:javascript
运行
复制
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

我如何才能以适应大型数据帧的方式实现相同的结果?

编辑:将我改进的解决方案移到答案部分。

EN

回答 1

Stack Overflow用户

发布于 2019-05-16 22:02:37

我成功地通过以下方式极大地提高了速度:

代码语言:javascript
运行
复制
def crop_random(dataset, output_length, ignore_na_tails=True):
    # Get a random range to crop for each row
    def get_range_crop(series, output_length, ignore_na_tails):
        series = np.array(series).astype('float')
        if ignore_na_tails:
            pos_non_na = np.where(~np.isnan(series))
            start = pos_non_na[0][0]
            end = pos_non_na[0][-1]
            left = np.random.randint(start,
                                     end - output_length + 2)  # +1 to include last in randint; +1 for slction span
        else:
            length = len(series)
            left = np.random.randint(0, length - output_length)
        right = left + output_length
        return left, right

    # Crop the rows to random range, reset_index to do concat without recreating new columns
    range_subset = dataset.apply(get_range_crop, args=(output_length,ignore_na_tails, ), axis = 1)
    new_rows = [dataset.iloc[irow, range_subset[irow][0]: range_subset[irow][1]]
                for irow in range(dataset.shape[0])]
    for row in new_rows:
        row.reset_index(drop=True, inplace=True)

    # Concatenate all rows
    dataset_cropped = pd.concat(new_rows, axis=1).T

    return dataset_cropped
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56127995

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档