python - 如何根据multiIndex DataFrame的内部索引进行操作?

标签 python pandas

假设我有一个学生成绩的 DataFrame,并且想要随时间跟踪他们的成绩。 DataFrame 可能如下所示:

data = [ { "Name": "John", "Period": 1, "Grade": 60 }, { "Name": "John", "Period": 2, "Grade": 80 }, { "Name": "John", "Period": 3, "Grade": 90 }, { "Name": "Bill", "Period": 1, "Grade": 80 }, { "Name": "Bill", "Period": 2, "Grade": 70 }, { "Name": "Bill", "Period": 3, "Grade": 80 }, { "Name": "Tom", "Period": 1, "Grade": 50 }, { "Name": "Tom", "Period": 2, "Grade": 75 }, { "Name": "Tom", "Period": 3, "Grade": 50 } ]

df = pd.DataFrame(data)
df.set_index(["Name", "Period"], inplace=True)

             Grade
Name Period       
John 1          60
     2          80
     3          90
Bill 1          80
     2          70
     3          80
Tom  1          50
     2          75
     3          50

现在我想添加一个“变化”列,显示每次考试的百分比变化。这些有点像堆叠的 DataFrame。如果是的话,我会尝试类似的事情

df["change"] = (df["Grade"] - df["Grade"].shift(1))/df["Grade"].shift(1)

这将在第一行中正确返回 NaN 值,因为它没有先前的值。对上述 DataFrame 执行此操作会产生:

             Grade    change
Name Period                 
John 1          60       NaN
     2          80  0.333333
     3          90  0.125000
Bill 1          80 -0.111111
     2          70 -0.125000
     3          80  0.142857
Tom  1          50 -0.375000
     2          75  0.500000
     3          50 -0.333333

我希望每个外部索引值的第一行“更改”值为 NaN,如下所示:

             Grade    change
Name Period                 
John 1          60       NaN
     2          80  0.333333
     3          90  0.125000
Bill 1          80       NaN
     2          70 -0.125000
     3          80  0.142857
Tom  1          50       NaN
     2          75  0.500000
     3          50 -0.333333

这也是后来聚合“更改”列时的情况,不会出现剧烈变化,因为一个学生的最终成绩会影响下一个学生的第一成绩。我知道有一些快捷方式可以简单地执行上述转换,然后将每个第一个“更改”值更改为 np.nan,但感觉必须有一种更优雅的方法。

最佳答案

使用GroupBy.pct_changeMultiIndex 的第一级:

df["change"] = df.groupby(level=0)['Grade'].pct_change()
print (df)
             Grade    change
Name Period                 
John 1          60       NaN
     2          80  0.333333
     3          90  0.125000
Bill 1          80       NaN
     2          70 -0.125000
     3          80  0.142857
Tom  1          50       NaN
     2          75  0.500000
     3          50 -0.333333

解决方案 DataFrameGroupBy.shift :

s = df.groupby(level=0)['Grade'].shift()
df["change"] = (df['Grade'] - s) / s

df["change"] =  df['Grade'].div(df.groupby(level=0)['Grade'].shift()).sub(1)

还有GroupBy.apply :

df["change"] = df.groupby(level=0)['Grade'].apply(lambda x: (x - x.shift())/ x.shift())

更好:

df["change"] = df.groupby(level=0)['Grade'].apply(lambda x: (x / x.shift()) - 1)

关于python - 如何根据multiIndex DataFrame的内部索引进行操作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55002118/

相关文章:

python - 如何通过字符串匹配加速 Pandas 行过滤?

python - ebook-convert 吐出 python 错误?有人能理解错误吗?

具有重复列类别的 Pandas 数据透视表

python - 如何在 re.search 失败的 Pandas 数据框中查找行

python - group-by/apply with Pandas 和 Multiprocessing

python - Pandas 基于 str.contains 合并

python - 如何通过 SqlAlchemy 中的 joinloaded 表进行过滤?

线程 Thread-1 中的 Python 异常(很可能在解释器关闭期间引发)?

python - Torch 数据集循环太远

python - Numpy:如何添加/加入切片对象?