根据条件棘手的重复行并在 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')]])
但是,我仍然需要为创建的新副本添加计数器。
任何建议表示赞赏。
尝试:
- 将您的日期列转换为时间戳
concat
您的原始数据与过滤后的数据
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.Period
为 Date
.
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
我有一个数据框,如果满足特定条件,我想基本上创建该行的副本。 行应该重复 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')]])
但是,我仍然需要为创建的新副本添加计数器。 任何建议表示赞赏。
尝试:
- 将您的日期列转换为时间戳
concat
您的原始数据与过滤后的数据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
forunit
(去除所有字符),pd.Period
为Date
.
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