如何从 Python 数据帧中行的前一个密集排名中读取值

How to read a value from the previous dense rank of the row in Python dataframe

我有 table.csv:

ID,X,X_2,X_3,Rank
XJ5,30,24,37,1
XK4,20,22,20,1
XK5,33,27,38,1
XK7,22,19,22,1
XJ5,33,22,21,2
XK4,20,22,22,2
XK5,33,24,29,2
XK6,23,21,22,2
XJ5,24,22,19,3
XK4,21,20,34,3
XK5,19,22,32,3
XK6,44,24,21,3
XK7,32,21,23,3

并希望输出 table:

ID,X,X_2,X_3,Rank,PrevX
XJ5,30,24,37,1,NA
XK4,20,22,20,1,NA
XK5,33,27,38,1,NA
XK7,22,19,22,1,NA
XJ5,33,22,21,2,30
XK4,20,22,22,2,20
XK5,33,24,29,2,33
XK6,23,21,22,2,NA
XJ5,24,22,19,3,33
XK4,21,20,34,3,20
XK5,19,22,32,3,33
XK6,44,24,21,3,23
XK7,32,21,23,3,NA

新的 PrevX 列是 Rank-1 行的 ID 的 X 值

这是我目前的情况:

import pandas
df = pandas.read_csv('table.csv')

更新

一种方法是:

  1. 使用 groupby 对每个 id 的数据进行分组,对每个组应用以下内容:
  2. rank 使用 sort_values
  3. 订购
  4. 创建一个临时列,其中 rank 使用 shift
  5. 移动一位
  6. 使用 add
  7. 添加 1 到这个新列
  8. 使用 np.where 将此新列与 rank 列进行比较:如果它们相等,则分配先前的 X 值,否则分配 NaN
  9. 可选以匹配预期输出:

这里是代码:

def get_previous(df):
    df = df.sort_values(by="Rank")
    df["rank_shifted"] = df.Rank.shift().add(1)
    df["PrevX"] = np.where(df.rank_shifted == df.Rank, df.X.shift(), np.NaN)
    return df

df = df.groupby('ID').apply(get_previous)
print(df)
#         ID   X  X_2  X_3  Rank  rank_shifted  PrevX
# ID
# XJ5 0  XJ5  30   24   37     1           NaN    NaN
#     3  XJ5  33   22   21     2           2.0   30.0
#     6  XJ5  24   22   19     3           3.0   33.0
# XK4 1  XK4  20   22   20     1           NaN    NaN
#     4  XK4  20   22   22     2           2.0   20.0
#     7  XK4  21   20   34     3           3.0   20.0
# XK5 2  XK5  33   27   38     1           NaN    NaN
#     5  XK5  33   24   29     2           2.0   33.0
#     8  XK5  19   22   32     3           3.0   33.0

# Match output
df = df.reset_index(drop=True).sort_values(by="Rank").drop("rank_shifted", axis=1)
print(df)
#     ID   X  X_2  X_3  Rank  PrevX
# 0  XJ5  30   24   37     1    NaN
# 3  XK4  20   22   20     1    NaN
# 6  XK5  33   27   38     1    NaN
# 1  XJ5  33   22   21     2   30.0
# 4  XK4  20   22   22     2   20.0
# 7  XK5  33   24   29     2   33.0
# 2  XJ5  24   22   19     3   33.0
# 5  XK4  21   20   34     3   20.0
# 8  XK5  19   22   32     3   33.0

原回答

假设排名总是由 3 行组成,您可以使用 shift:

df["PrevX"] = df.X.shift(3)
print(df)
#     ID   X  X_2  X_3  Rank  PrevX
# 0  XJ5  30   24   37     1    NaN
# 1  XK4  20   22   20     1    NaN
# 2  XK5  33   27   38     1    NaN
# 3  XJ5  33   22   21     2   30.0
# 4  XK4  20   22   22     2   20.0
# 5  XK5  33   24   29     2   33.0
# 6  XJ5  24   22   19     3   33.0
# 7  XK4  21   20   34     3   20.0
# 8  XK5  19   22   32     3   33.0

如果您不知道每个 rank 组的行数,您可以使用 groupbysize 找到它:

print(df.groupby('Rank').size())
# Rank
# 1    3
# 2    3
# 3    3

希望对您有所帮助!

我认为groupbyshift如下:
_ groupbyRank 上找到 diff1 创建掩码 m 以根据条件 [=] 识别哪个 ID 具有价值14=] 是相邻的 (Rank-1)。 Rank-1 内任何相同的 ID 将被标记为 True,否则 False
_ groupby IDshift X
_ 最后,使用 where 和掩码 mm 中的 False 翻转为 NaN

m = df.groupby('ID').Rank.diff().eq(1)
df['prevX'] = df.groupby('ID').X.shift().where(m)

Out[28]:
     ID   X  X_2  X_3  Rank  prevX
0   XJ5  30   24   37     1    NaN
1   XK4  20   22   20     1    NaN
2   XK5  33   27   38     1    NaN
3   XK7  22   19   22     1    NaN
4   XJ5  33   22   21     2   30.0
5   XK4  20   22   22     2   20.0
6   XK5  33   24   29     2   33.0
7   XK6  23   21   22     2    NaN
8   XJ5  24   22   19     3   33.0
9   XK4  21   20   34     3   20.0
10  XK5  19   22   32     3   33.0
11  XK6  44   24   21     3   23.0
12  XK7  32   21   23     3    NaN