根据条件棘手地重复行,并在 Python 中添加一个计数器



我有一个数据帧,如果满足某个条件,我想基本上创建该行的副本。如果"日期"= Q4.22 或> AND 类型 = "实时",则应复制行此外,对于创建的每个重复项,应更新"单位"计数以反映这一点(按 id 和日期分组)建立重复项后,单位计数应反映基于相同 id 和日期的新计数。

数据

id   Date    set     type    unit    energy
bb   Q4.22   l       live    l01     20
bb   Q4.22   l       live    l02     20
ba   Q3.22   l       non     l01     20
aa   Q4.22   l       non     l01     20
aa   Q4.22   l       live    l01     20
cc   Q3.22   l       non     l01     20
aa   Q4.22   l       live    l02     20

期望

id   Date    set     type    unit    energy
bb   Q4.22   l       live    l01     20
bb   Q4.22   l       live    l02     20
bb   Q4.22   l       live    l03     20
bb   Q4.22   l       live    l04     20
ba   Q3.22   l       non     l01     20
aa   Q4.22   l       non     l01     20
aa   Q4.22   l       live    l01     20
aa   Q4.22   l       live    l02     20
cc   Q3.22   l       non     l01     20
aa   Q4.22   l       live    l03     20
aa   Q4.22   l       live    l04     20

行为

pd.concat([df, df.loc[(df['Date'] == > 'Q4.22') & (df['live'] == 'live')]])

但是,我仍然需要向创建的新副本添加计数器。 任何建议不胜感激。

尝试:

  1. 将日期列转换为时间戳
  2. 使用过滤后的数据concat原始数据
  3. groupby获取"id"和"Date"的cumcount并相应地设置"单位">
df["Date"] = pd.to_datetime(df["Date"].str.replace(r"(Qd).(d+)", r"2-1",regex=True))
output = pd.concat([df, df[df["Date"].ge(pd.Timestamp("2022-10-01"))&df["type"].eq("live")]], ignore_index=True)
output["unit"] = output["set"]+output.groupby(["id", "Date"]).cumcount().add(1).astype(str).str.zfill(2)
output = output.sort_values("id", ignore_index=True)
#convert Date back to original format if needed
output["Date"] = output["Date"].dt.to_period("Q").astype(str).str.replace(r"dd(d+)(Qd)",r"2.1",regex=True)
>>> output
id   Date set  type unit  energy
0   aa  Q4.22   l   non  l01      20
1   aa  Q4.22   l  live  l02      20
2   aa  Q4.22   l  live  l03      20
3   aa  Q4.22   l  live  l04      20
4   aa  Q4.22   l  live  l05      20
5   ba  Q3.22   l   non  l01      20
6   bb  Q4.22   l  live  l01      20
7   bb  Q4.22   l  live  l02      20
8   bb  Q4.22   l  live  l03      20
9   bb  Q4.22   l  live  l04      20
10  cc  Q3.22   l   non  l01      20

首先,如注释中所述,我们需要将一些 df 列转换为更方便的类型:

  • intunit(去除任何字符),
  • pd.PeriodDate.
df2 = df.assign(
unit=df['unit'].str.extract(r'(d+)').astype(int),
period=df['Date'].str.replace(r'^(Qd)D*(d+)$', r'21', regex=True).apply(pd.Period)
)
>>> df2
id   Date set  type  unit  energy  period
0  bb  Q4.22   l  live     1      20  2022Q4
1  bb  Q4.22   l  live     2      20  2022Q4
2  ba  Q3.22   l   non     1      20  2022Q3
3  aa  Q4.22   l   non     1      20  2022Q4
4  aa  Q4.22   l  live     1      20  2022Q4
5  cc  Q3.22   l   non     1      20  2022Q3
6  aa  Q4.22   l  live     2      20  2022Q4
>>> df2.dtypes
id               object
Date             object
set              object
type             object
unit              int64
energy            int64
period    period[Q-DEC]
dtype: object

完成此操作后,现在我们可以继续问题本身的逻辑。

ix_repeat = (df2['period'] >= pd.Period('2022-Q4')) & (df2['type'] == 'live')
r = df2.loc[ix_repeat]
r.assign(unit=r['unit'] + r.groupby(['id', 'period'])['unit'].transform(max))
>>> r
id   Date set  type  unit  energy  period
0  bb  Q4.22   l  live     3      20  2022Q4
1  bb  Q4.22   l  live     4      20  2022Q4
4  aa  Q4.22   l  live     3      20  2022Q4
6  aa  Q4.22   l  live     4      20  2022Q4
# finally
df2 = pd.concat([df2, r])

可选:将单元恢复到其奇怪的字符串版本:

df2 = df2.assign(unit=df2['set'] + df2['unit'].astype(str).str.zfill(2))
>>> df2
id   Date set  type unit  energy  period
0  bb  Q4.22   l  live  l01      20  2022Q4
1  bb  Q4.22   l  live  l02      20  2022Q4
2  ba  Q3.22   l   non  l01      20  2022Q3
3  aa  Q4.22   l   non  l01      20  2022Q4
4  aa  Q4.22   l  live  l01      20  2022Q4
5  cc  Q3.22   l   non  l01      20  2022Q3
6  aa  Q4.22   l  live  l02      20  2022Q4
0  bb  Q4.22   l  live  l03      20  2022Q4
1  bb  Q4.22   l  live  l04      20  2022Q4
4  aa  Q4.22   l  live  l03      20  2022Q4
6  aa  Q4.22   l  live  l04      20  2022Q4

最新更新