计算首次出现和各个位置之间的差异(Python Pandas)

3

让我们以一个简单的人力资源数据框为例:

姓名 年份 部门 薪资 新增列:hit100after
约翰 2018 研发 80 0
玛丽 2018 法务 90 0
吉尔 2018 法务 100 0
约翰 2019 研发 85 0
玛丽 2019 法务 95 0
吉尔 2019 法务 105 1
约翰 2020 研发 90 0
玛丽 2020 法务 100 2
吉尔 2020 法务 110 2

问题: 在同一部门的第一个人达到薪资>=100之后,需要多长时间(以年为单位)才能使任何数据集达到相同的薪资? (请参见新列'hit100after')

实际上,我在实现时遇到了困难。我的步骤将是按部门分组,并找到薪资>=100的第一次出现,并用新的布尔类型或第二个数据帧标记该年份。然后,我将计算个体薪资>=100与其部门中第一次出现的差异。

有什么想法可以为大型数据帧编写这样的代码吗?


在Jill 2018中,hit100after的数量应该是1吗? - Para
100第一次在2018年出现在法律中。因此,hit100after的值只能为0,因为自这个“事件发生”以来还没有过去任何年份。 - GGCoolP
2个回答

3
你可以使用 groupby() 函数按照 Department 进行分组,然后找到满足条件 Salary >= 100 的最小年份 Year.min()
first100 = df.groupby('Department').apply(
    lambda g: g[g.Salary >= 100].Year.min())

# Department
# Legal    2018.0
# R&D         NaN
# dtype: float64

然后按照 Departmentfirst100 年进行 map(),并从 Year 中减去。结果保存在 Result 中以供比较:

df['Result'] = df.Year - df.Department.map(first100)
df.loc[df.Salary < 100, 'Result'] = 0

#     Name  Year Department  Salary  Hit100after  Result
# 0   John  2018        R&D      80            0     0.0
# 1  Marie  2018      Legal      90            0     0.0
# 2   Jill  2018      Legal     100            0     0.0
# 3   John  2019        R&D      85            0     0.0
# 4  Marie  2019      Legal      95            0     0.0
# 5   Jill  2019      Legal     105            1     1.0
# 6   John  2020        R&D      90            0     0.0
# 7  Marie  2020      Legal     100            2     2.0
# 8   Jill  2020      Legal     110            2     2.0

当前答案的时间

方法 使用100万行的%timeit时间
这个答案 3.07毫秒 ± 23.1微秒每次循环(平均值±7次运行的标准差,每次100次循环)
query()答案 4.33毫秒 ± 354微秒每次循环(平均值±7次运行的标准差,每次100次循环)

2
你可以尝试以下方法:
new_col = (df.query("Salary >= 100")
             .groupby("Department")
             .apply(lambda x: x.Year - x.iloc[0].Year)
             .reset_index(level=0, drop=True)
             .T)
df["hit100after"] = new_col
df["hit100after"] = df["hit100after"].fillna(0).astype(int)

首先,我们查看薪水大于100的条目(查询),然后按部门分组(groupby),应用函数以获取相对于部门中第一个条目的年份差异(apply和iloc[0]),去掉部门名称(在0级上使用reset_index,并将drop设置为True),并进行转置(T)以确保其垂直以便与原始df对齐。
最后,我们将这个新列分配给df,但由于我们只选择了那些Salary >= 100的条目,因此在分配时会出现NaN;因此需要使用fillna(0)。由于NaN在技术上是浮点数,所以最后我们将其转换为int。
    Name  Year Department  Salary  hit100after
0   John  2018        R&D      80            0
1  Marie  2018      Legal      90            0
2   Jill  2018      Legal     100            0
3   John  2019        R&D      85            0
4  Marie  2019      Legal      95            0
5   Jill  2019      Legal     105            1
6   John  2020        R&D      90            0
7  Marie  2020      Legal     100            2
8   Jill  2020      Legal     110            2

1
+1 我很少看到 query,所以很高兴看到它被使用。出于好奇我计时了一下,似乎比我的版本略慢一点。 - tdy
1
@tdy,你的代码更加简洁、易读和健壮(例如,我的代码在索引存在重复时会失败),而且速度更快(我尝试了一个包含多个部门且每个部门都有100个以上数据的数据框,速度比你的代码慢了一倍)。我还有很多需要学习的地方! - Mustafa Aydın
1
非常感谢你们俩,你们帮了我很大的忙,两种解决方案都使我达到了想要的效果!你们的解释帮助我理解了你们所做的事情,并让我能够自己完成类似的任务。 - GGCoolP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接