有效日期范围一键编码groupby

Chr*_*arr 6 python pandas dask pandas-groupby

从此样本数据开始...

import pandas as pd

start_data = {"person_id": [1, 1, 1, 1, 2], "nid": [1, 2, 3, 4, 1],
              "beg": ["Jan 1 2018", "Jan 5 2018", "Jan 10 2018", "Feb 5 2018", "Jan 25 2018"],
              "end": ["Feb 1 2018", "Mar 4 2018", "", "Oct 18 2018", "Nov 10 2018"]}
df = pd.DataFrame(start_data)
df["beg"] = pd.to_datetime(df["beg"])
df["end"] = pd.to_datetime(df["end"])
Run Code Online (Sandbox Code Playgroud)

初始点:

   person_id  nid        beg        end
0          1    1 2018-01-01 2018-02-01
1          1    2 2018-01-05 2018-03-04
2          1    3 2018-01-10        NaT
3          1    4 2018-02-05 2018-10-18
4          2    1 2018-01-25 2018-11-10
Run Code Online (Sandbox Code Playgroud)

目标输出:

person_id date       1 2 3 4
        1 2018-01-01 1 0 0 0
        1 2018-01-05 1 1 0 0
        1 2018-01-10 1 1 1 0
        1 2018-02-01 0 1 1 0
        1 2018-02-05 0 1 1 1
        1 2018-03-04 0 0 1 1
        1 2018-10-18 0 0 1 0 
        2 2018-01-25 1 0 0 0
        2 2018-11-10 0 0 0 0
Run Code Online (Sandbox Code Playgroud)

我正在尝试将所有活动对象nid与关联的对象绑定在一起。person_id然后,该对象将根据最新的,date少于日期的活动列,加入另一个数据框。最后,这将成为预测模型输入的一部分。

做类似pd.get_dummies(df["nid"])get的输出:

   1  2  3  4
0  1  0  0  0
1  0  1  0  0
2  0  0  1  0
3  0  0  0  1
4  1  0  0  0
Run Code Online (Sandbox Code Playgroud)

因此,需要将其移动到代表生效日期的其他索引(按进行分组)person_id,然后进行汇总以匹配目标输出。

凡是想出一种可以适当利用Dask的方法的人,都能获得特别的奖励。由于可伸缩性,这就是我们在流水线的其他部分使用的东西。这可能是个白日梦,但我想我会把它寄出去,看看会回来什么。

Chr*_*arr 0

beg_col这是一个基于有效日期范围对数据进行单热编码的函数end_col。需要注意的一种极端情况是同一target列有多个开始生效日期。您可以向函数添加一些巧妙的过滤来处理该问题,但我将在这里保留简单的版本。

def effective_date_range_one_hot_encode(x, beg_col="beg", end_col="end", target="nid"):
    pos_change = x.loc[:, [beg_col, target]]
    pos_change = pos_change.set_index(beg_col)
    pos_change = pd.get_dummies(pos_change[target])

    neg_change = x.loc[:, [end_col, target]]
    neg_change = neg_change.set_index(end_col)
    neg_change = pd.get_dummies(neg_change[target]) * -1

    changes = pd.concat([pos_change, neg_change])

    changes = changes.sort_index()
    changes = changes.cumsum()

    return changes


new_df = df.groupby("person_id").apply(effective_date_range_one_hot_encode).fillna(0).astype(int)
new_df.index = new_df.index.set_names(["person_id", "date"])
new_df = new_df.reset_index()
new_df = new_df.dropna(subset=["date"], how="any")
Run Code Online (Sandbox Code Playgroud)

该函数可以使用应用.groupby(),如果您需要在分布式环境中运行该函数,您可以.map_partitions()在 Dask 中使用该函数。只需首先将索引设置为您计划的列,groupby然后创建一个辅助函数来重置索引。

输出

   person_id effective_date  1  2  3  4
0          1     2018-01-01  1  0  0  0
1          1     2018-01-05  1  1  0  0
2          1     2018-01-10  1  1  1  0
3          1     2018-02-01  0  1  1  0
4          1     2018-02-05  0  1  1  1
5          1     2018-03-04  0  0  1  1
6          1     2018-10-18  0  0  1  0
8          2     2018-01-25  1  0  0  0
9          2     2018-11-10  0  0  0  0
Run Code Online (Sandbox Code Playgroud)