Python pandas:根据多个字段的多个条件识别记录

时间:2015-01-08 23:06:05

标签: python pandas dataframe

将IPython(Python 3.4)与pandas一起使用:我有一个大致相似的数据框(注意每个学生的重复记录,有时每个学生有3个以上):

Year    Subject   Student   Score   Date
2014    Math       1        34     31-Jan
2014    Math       1        34     26-Jan
2014    Math       2        65     26-Jan
2014    Math       2        76     31-Jan
2014    Math       3        45     3-Feb
2014    Math       3        67     31-Jan

我正在寻找一种方法,根据以下标准返回每位学生的分数: 1.得分最高 当每个学生的记录中的分数相同时: 2.最近的日期

这是所需的输出:

Year    Subject   Student   Score   Date
2014    Math       1        34     31-Jan
2014    Math       2        76     31-Jan
2014    Math       3        67     31-Jan

这是我迄今为止所尝试的内容: 使用年份,科目和学生的groupby获得给定年份和学科领域的每位学生的最高分数:

by_duplicate = df.groupby(['Year', 'Subject', 'Student'])
HighScore = by_duplicate[['Year', 'Subject', 'Student', 'Score']].max()

在这里,我重命名得分列,以便当我将其加入到原始数据帧时,我知道哪个列是哪个。这可能没有必要,但我不确定。

HighScore.rename(columns={'Score': 'Score2'}, inplace=True)

在这里,我添加了空白' HighScore'如果该行具有最高分数,则预期将在以后填充1的列。稍后会详细介绍......

HighScore['HighScore'] = ""

然后我在最近的日期做同样的事情:

Recent = by_duplicate[['Year', 'Subject', 'Student', 'Date']].max()
Recent.rename(columns={'Date': 'Date2'}, inplace=True)
Recent['Recent'] = ""

My approach was to 
1. create tables for each field (score and date) using groupby, 
2. identify the rows containing the highest and most recent scores, respectively, by entering a "1" in their respective new columns (HighScore' and 'Recent')
3. somehow join these grouped tables back to the original dataframe on Year, Subject, and Student
-I'm guessing this requires somehow ungrouping the groups as the pd.merge is not working on the grouped data frames
4. The end result, according to my theory, would look something like this:

Year    Subject   Student   Score   Date     HighScore  Recent
2014    Math       1        34     31-Jan    1          1   
2014    Math       1        34     26-Jan    1          0
2014    Math       2        65     26-Jan    0          0  
2014    Math       2        76     31-Jan    1          1  
2014    Math       3        45     3-Feb     0          1  
2014    Math       3        67     31-Jan    1          0

And once I have this table, I would need to do something like this:
1. Per student for a given year and subject area: return the sum of 'HighScore'
2. If the sum of 'HighScore' is greater than 1, then take the 'Recent' row equal to 1.
I believe this will give me what I need.

提前致谢!!!

1 个答案:

答案 0 :(得分:1)

如果我正确地关注,我认为你可以通过对得分和日期进行排序来简化这一点,这样每个组的最后一个元素总是最高得分。我可能会做类似

的事情
>>> df["FullDate"] = pd.to_datetime(df["Year"].astype(str) + "-" + df["Date"], 
                     format="%Y-%d-%b")
>>> df = df.sort(["Score", "FullDate"])
>>> df.groupby(["Year", "Subject", "Student"]).tail(1)
   Year Subject  Student  Score    Date   FullDate
0  2014    Math        1     34  31-Jan 2014-01-31
5  2014    Math        3     67  31-Jan 2014-01-31
3  2014    Math        2     76  31-Jan 2014-01-31

首先我创建一个FullDate列,这是一个真正的日期时间而不是字符串,所以我知道它会正确排序。

请注意,我们排序的顺序很重要:我们首先要按分数,然后在最大分数内,最后“最大”(最近)日期。相反,如果我们以另一种方式完成它,我们就有了

>>> df = df.sort(["FullDate", "Score"]) # THIS IS THE WRONG ORDER
>>> df.groupby(["Year", "Subject", "Student"]).tail(1)
   Year Subject  Student  Score    Date   FullDate
0  2014    Math        1     34  31-Jan 2014-01-31
3  2014    Math        2     76  31-Jan 2014-01-31
4  2014    Math        3     45   3-Feb 2014-02-03

这将在最近一天给我们最高分。

现在确实排序为~O(N log N)并且找到最大值可以在O(N)中完成,但恕我直言,简单性大大超过通常较小的性能损失。