随着时间线的增加,根据最高和最低行值过滤 Dataframe

Filter Dataframe Based on Highest and Lowest Row Values with Increasing Timeline

我有以下学生的数据框,他们的考试成绩在不同的日期(排序):

df = pd.DataFrame({'student': 'A A A A B B B C C D D'.split(),
                  'exam_date':[datetime.datetime(2013,4,1),datetime.datetime(2013,6,1),
                               datetime.datetime(2013,7,1),datetime.datetime(2013,9,2),
                               datetime.datetime(2013,10,1),datetime.datetime(2013,11,2),
                               datetime.datetime(2014,2,2),datetime.datetime(2014,5,2),
                               datetime.datetime(2014,6,2), datetime.datetime(2013,7,1),
                               datetime.datetime(2013,9,2),],
                   'score': [15, 22, 32, 20, 30, 38, 26, 18, 30, 33, 40]})

print(df)

   student  exam_date  score
0        A 2013-04-01     15
1        A 2013-06-01     22
2        A 2013-07-01     32
3        A 2013-09-02     20
4        B 2013-10-01     30
5        B 2013-11-02     38
6        B 2014-02-02     26
7        C 2014-05-02     18
8        C 2014-06-02     30
9        D 2013-07-01     33
10       D 2013-09-02     40

我只需要保留那些最高分比最低分增加 10 以上的行,否则删除它们。在这里,日期也很重要。最高分必须在比前一天更晚的日期。

例如,对于学生 A,最低分数是 15,分数增加到 32(日期较晚),所以我们要保留那。

学生B的最低分是26,但之后就没有再增加了。它基本上减少了,所以我们要放弃它。

学生D,最低分是33,分数提高到40,只增加了7,所以我们要降了那。

我第一次尝试 df.groupby('student').agg({'score': np.ptp}) 但很难跟踪分数是减少还是增加。

然后我尝试使用 df.loc[df.groupby('student')['score'].idxmin()]df.loc[df.groupby('student')['score'].idxmax()] 来获取最小值和值,但不确定如何比较日期。也许我合并它们然后比较,但是工作量太大了。

期望输出:

student exam_date   score
2   A   2013-07-01  32
8   C   2014-06-02  30

#--For A, highest score of 32 increased by 17 from lowest score of 15  
#--For C, highest score of 30 increased by 12 from lowest score of 18 

最聪明的做法是什么?任何建议,将不胜感激。谢谢!

所以在你的情况下,首先按最小值过滤

df = df[df.index>=df.groupby('student')['score'].transform('idxmin')]
out = df[df.score - df.groupby('student').score.transform('min')>10]
Out[77]: 
  student  exam_date  score
2       A 2013-07-01     32
8       C 2014-06-02     30

假设您的数据框已按日期排序:

highest_score = lambda x: x['score'].cummax() * (x['score'] > x['score'].shift()) \
                          - (x['score'].cummin()) >= 10

out = df[df.groupby('student').apply(highest_score).droplevel(0)]
print(out)

# Output:
  student  exam_date  score
2       A 2013-07-01     32
8       C 2014-06-02     30

表达式 * (x['score'] > x['score'].shift()) 避免 cummax 在下一个值低于当前最大值时传播

这个问题有点令人困惑,但这适用于您的示例数据:

subset = df.loc[df.groupby('student').apply(lambda x: x['score'].idxmax() if x.sort_values('exam_date')['score'].diff().max() >= 10 else None).dropna().astype(int)]

输出:

>>> subset
  student  exam_date  score
2       A 2013-07-01     32