随着时间线的增加,根据最高和最低行值过滤 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
我有以下学生的数据框,他们的考试成绩在不同的日期(排序):
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