numpy 一种有效的方法,将基于条件的值从一个pandas数组中获取到另一个pandas数组中

lp0sw83n  于 5个月前  发布在  其他
关注(0)|答案(2)|浏览(44)

我有两个数据集。一个包含300多万个提议的轮班。你可以把数据想象成类似于
| 天|开始|端|员工ID|店铺ID|班次ID|
| --|--|--|--|--|--|
| 二〇二〇年十二月十七日|16点了。|22点整|123456号。| 123 | 12345 |
| 二〇二〇年十二月十三日|17点整。|23点整|第2889785号。| 321 | 34346 |

一名员工可以在同一天内执行多个轮班

第二个数据集是一组400万次的打卡记录。2这些打卡记录是工人在他们实际轮班时打卡上班/打卡外出吃午饭/打卡下班/打卡外出的记录。
数据如下所示
| 员工标识|店铺ID|打孔代码|Punch time|打卡日期|
| --|--|--|--|--|
| 123456 | 123 |IN.| 16点整。|二〇二〇年十二月十七日|
| 2889785 | 321 |出去|23点整|二〇二〇年十二月十三日|
| 123456 |123号|出去吃午饭。|十七点十分。|二〇二〇年十二月十七日|
我需要创建一个 Dataframe ,最好如下所示
| 员工标识|店铺ID|打孔代码|Punch time|打卡日期|班次ID|
| --|--|--|--|--|--|
| 123456 | 123 |IN.| 16点整。|二〇二〇年十二月十七日|12345号。|
| 2889785 | 321 |出去|23点整|二〇二〇年十二月十三日| 34346 |
| 123456 |123号|出去吃午饭。|十七点十分。|二〇二〇年十二月十七日|12345号。|
我更喜欢合并,其中On位于store、worker、id上,然后是|||如果打卡时间在给定的班次范围内|||
但据我所知,您不能进行条件合并?
我似乎想不出一种方法来做这对Pandas
我已经尝试过循环超过帧列表的字典,但这将需要很长很长的时间,因为它需要这么多的嵌套循环。
我还考虑过构造一个apply函数,它包含store、time和id,并找到所讨论的shift,将id返回到列中。我认为这是最简洁、最令人满意的方法,但我认为这也太耗时了。
这感觉就像必须有一个“矢量化”的方式来实现这一点,但也许不是-任何帮助都将非常感激。

e1xvtsh3

e1xvtsh31#

您可以尝试通过首先创建 index 来尽量减少搜索-在本例中,组字典的键是Day/Store ID/Worker ID

# create datetime objects from df1
df1["Shift_Start"] = pd.to_datetime(df1["Day"] + " " + df1["Start"])
df1["Shift_End"] = pd.to_datetime(df1["Day"] + " " + df1["End"])

# cretate punch datetime object
df2["Punch_Time"] = pd.to_datetime(df2["Punch Date"] + " " + df2["Punch time"])

# create groups for easy searching
groups_day_store_worker_id = {
    idx: g for idx, g in df1.groupby(["Day", "Store ID", "Worker ID"])
}

def get_shift_id(row):
    group = groups_day_store_worker_id.get(
        (row["Punch Date"], row["Store ID"], row["Worker Id"])
    )
    if group is None:
        return None

    punch_time = row["Punch_Time"]
    for s, e, shift_id in zip(
        group["Shift_Start"], group["Shift_End"], group["Shift ID"]
    ):
        if s <= punch_time <= e:
            return shift_id

    return None

df2["Shift ID"] = df2.apply(get_shift_id, axis=1)
print(df2)

字符串
印刷品:

Worker Id  Store ID Punch Code Punch time  Punch Date          Punch_Time  Shift ID
0     123456       123         IN      16:00  12/17/2020 2020-12-17 16:00:00     12345
1    2889785       321        OUT      23:00  12/13/2020 2020-12-13 23:00:00     34346
2     123456       123  LUNCH OUT      17:10  12/17/2020 2020-12-17 17:10:00     12345

qlvxas9a

qlvxas9a2#

一种方法是将班次数据与打孔数据合并,然后为打孔时间介于开始时间和结束时间之间的行创建掩码,以选择所需的行。首先,我必须清理示例数据(您可能不需要这样做):

shifts['Day'] = pd.to_datetime(shifts['Day'])
shifts['Start'] = shifts['Start'].str.strip('. ')
shifts['Worker ID'] = shifts['Worker ID'].astype(int)

punchs['Store ID'] = punchs['Store ID'].astype(int)
punchs['Punch time'] = punchs['Punch time'].str.strip(' .')
punchs['Punch Date'] = pd.to_datetime(punchs['Punch Date'])

字符串
然后我们可以处理它:

out = punchs.merge(shifts, 
     left_on=['Worker Id', 'Store ID', 'Punch Date'],
     right_on=['Worker ID', 'Store ID', 'Day'], 
     how='inner')
mask = (out['Start'] <= out['Punch time']) & (out['Punch time'] <= out['End'])
out = out[mask].drop(columns=['Day', 'Start', 'End', 'Worker ID'])


示例数据的输出:

Worker Id  Store ID   Punch Code Punch time Punch Date  Shift ID
0     123456       123         IN.       16:00 2020-12-17     12345
1     123456       123  LUNCH OUT.       17:10 2020-12-17     12345
2    2889785       321        OUT.       23:00 2020-12-13     34346

相关问题