我知道在stackoverflow上已经有很多类似的问题,但我就是找不到任何东西,也想不出我自己的解决方案……我们开始吧:
我对一组不断变化的数据X运行一致性检查,每次运行都可能会发现一些冲突。我可以用一个独特的key来识别违规的案例。一旦在原始数据集X中解决了冲突,该冲突显然会从检查中消失。违规可能会在以后重新出现,然后应该被视为新的。
每次运行检查时,我都会创建一个日志文件,其中记录了违规的date和key。
从此日志文件中,我想提取日志文件中处于打开状态的案例/违规的数量,以及在任何日期累计关闭的案例的数量:

这是左表的另一个变换,它可能有助于理解结果( (.)中的数字)请参考左表中的对应行):

AAA在2020年5月1日开放,2020年5月4日关闭,因为2020年5月4日没有AAA的条目,但我们知道测试是在那个日期运行的(6)。
AAA在2020年5月5日关闭后再次打开,并在2020年5月7日关闭,因为测试在那一天运行,而AAA不再出现(8)。5/6/2020从未出现过。
BBB在2020年5月2日开放,并在2020年5月7日期间出现,因此从未关闭。
下面是框架代码:
df = pd.DataFrame(
{
"date": [
"5/1/2020",
"5/2/2020",
"5/3/2020",
"5/5/2020",
"5/2/2020",
"5/3/2020",
"5/4/2020",
"5/5/2020",
"5/7/2020",
],
"key": ["AAA"] * 4 + ["BBB"] * 5,
}
)
df['date'] = df['date'].astype("datetime64")我相信我必须使用日期阶梯(date_ladder = df[['date']].drop_duplicates().sort_values(by='date')),并与df进行外部合并,以获得所有日期的每个键的值,然后从那里继续。但是我已经在那里创建合并失败了。
发布于 2020-05-08 16:54:16
所以,这是在睡了一觉之后的尝试…首先,我们将添加一个虚拟变量,然后在数据帧上旋转,并再次将其融化:
df['v'] = True
pvt = df.pivot_table(index='date', columns='key', values='v').fillna(False)
df2 = pvt.reset_index().melt(id_vars='date')
"""
df2:
date key value
0 2020-05-01 AAA True
1 2020-05-02 AAA True
2 2020-05-03 AAA True
3 2020-05-04 AAA False
4 2020-05-05 AAA True
5 2020-05-07 AAA False
6 2020-05-01 BBB False
7 2020-05-02 BBB True
8 2020-05-03 BBB True
9 2020-05-04 BBB True
10 2020-05-05 BBB True
11 2020-05-07 BBB True
"""现在我们将数据帧移位1,然后检查是否存在从True到False的切换(反之亦然),这表明原始日志文件中出现或消失了一条记录:
df2['switch'] = (df2['value'] ^ df2.shift()['value']) |( (df2['key']!=df2.shift()['key']) & df2['value'])
df2['start'] = df2['switch'] & df2['value']
df2['end'] = df2['switch'] & ~df2['value']
df2['status'] = ''
df2.loc[df2['start'], 'status'] = 'Start'
df2.loc[df2['end'], 'status'] = 'End'
"""
date key value switch start end status
0 2020-05-01 AAA True True True False Start
1 2020-05-02 AAA True False False False
2 2020-05-03 AAA True False False False
3 2020-05-04 AAA False True False True End
4 2020-05-05 AAA True True True False Start
5 2020-05-07 AAA False True False True End
6 2020-05-01 BBB False False False False
7 2020-05-02 BBB True True True False Start
8 2020-05-03 BBB True False False False
9 2020-05-04 BBB True False False False
10 2020-05-05 BBB True False False False
11 2020-05-07 BBB True False False False
"""我们可以用pd.melt()压缩一下
df3 = df2.loc[df2['status']!=''].melt(id_vars=['key', 'status'], value_vars='date', value_name='date').drop('variable', axis=1)
"""
key status date
0 AAA Start 2020-05-01
1 AAA End 2020-05-04
2 AAA Start 2020-05-05
3 AAA End 2020-05-07
4 BBB Start 2020-05-02
"""下一步是按日期对数据进行排序,因为我们想知道在任何时候有多少项处于打开或关闭状态。
df4 = df2.sort_values(by='date')
df4['opened'] = df4['start'].cumsum()
df4['closed'] = df4['end'].cumsum()
"""
date key value switch ... end status opened closed
0 2020-05-01 AAA True True ... False Start 1 0
6 2020-05-01 BBB False False ... False 1 0
1 2020-05-02 AAA True False ... False 1 0
7 2020-05-02 BBB True True ... False Start 2 0
2 2020-05-03 AAA True False ... False 2 0
8 2020-05-03 BBB True False ... False 2 0
3 2020-05-04 AAA False True ... True End 2 1
9 2020-05-04 BBB True False ... False 2 1
4 2020-05-05 AAA True True ... False Start 3 1
10 2020-05-05 BBB True False ... False 3 1
5 2020-05-07 AAA False True ... True End 3 2
11 2020-05-07 BBB True False ... False 3 2
"""最后,我们将运行一个groupby(),计算在特定日期打开了多少个项目,并绘制结果:
result = df4.groupby('date').agg(opened=pd.NamedAgg(column='opened', aggfunc='max'), closed = pd.NamedAgg(column='closed', aggfunc='max'))
result['open_on'] = result['opened']-result['closed']
result[['closed', 'open_on']].plot.area()

https://stackoverflow.com/questions/61661846
复制相似问题