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

Tricky duplicate rows based on condition and add a counter in Python

我有一个数据框,如果满足特定条件,我想基本上创建该行的副本。 行应该重复 IF 'Date' = Q4.22 or > AND type = 'live' 此外,对于每个创建的副本,'unit' 计数应该更新以反映这一点(按 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并相应设置“unit”
df["Date"] = pd.to_datetime(df["Date"].str.replace(r"(Q\d).(\d+)", r"-",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"\d\d(\d+)(Q\d)",r".",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 列转换为更方便的类型:

  • int for unit(去除所有字符),
  • pd.PeriodDate.
df2 = df.assign(
    unit=df['unit'].str.extract(r'(\d+)').astype(int),
    period=df['Date'].str.replace(r'^(Q\d)\D*(\d+)$', r'', 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