pandas dataframe,按另一列中的值排序,而不使用Python FOR循环

pandas dataframe,按另一列中的值排序,而不使用Python FOR循环,python,pandas,dataframe,Python,Pandas,Dataframe,对于一列中的每个值(我下面的示例中的“日期”),我希望根据另一列中的值(我的示例中的“值”列)进行排名 我的代码可以工作,但我想知道如果没有Pythonfor循环,它是否可以完成 data = {'code': ['AAA', 'AAA', 'AAA', 'BBB', 'BBB', 'BBB', 'CCC', 'CCC', 'CCC'], 'date': ['2001-01-01', '2001-01-02', '2001-01-03', '2001-01-01', '2001-

对于一列中的每个值(我下面的示例中的“日期”),我希望根据另一列中的值(我的示例中的“值”列)进行排名

我的代码可以工作,但我想知道如果没有Pythonfor循环,它是否可以完成

data = {'code': ['AAA', 'AAA', 'AAA', 'BBB', 'BBB', 'BBB', 'CCC', 'CCC', 'CCC'],
        'date': ['2001-01-01', '2001-01-02', '2001-01-03', '2001-01-01', '2001-01-02', '2001-01-03', '2001-01-01', '2001-01-02', '2001-01-03'],
        'value': [32, 23, 34, 23, 34, 12, 28, 39, 40]}
df = pd.DataFrame(data)
print(df)

pd.set_option('mode.chained_assignment', None)
result = pd.DataFrame()
for date in df['date'].unique():
    sub = df[df['date'] == date]
    sub['rank'] = len(sub) - sub['value'].rank() + 1
    result = result.append(sub[['code', 'date', 'rank']])
pd.set_option('mode.chained_assignment', 'warn')
df2 = pd.merge(df, result, on=['code', 'date'])

print(df2.sort_values(['date', 'code']))  # within each date, rows are ranked by value

我能在不迭代Python for循环的情况下得到相同的结果吗?

让我们使用
groupby
进行
rank

df['rank'] = df.groupby('code')['value'].rank()
df
Out[491]: 
  code        date  value  rank
0  AAA  2001-01-01     32   2.0
1  AAA  2001-01-02     23   1.0
2  AAA  2001-01-03     34   3.0
3  BBB  2001-01-01     23   2.0
4  BBB  2001-01-02     34   3.0
5  BBB  2001-01-03     12   1.0
6  CCC  2001-01-01     28   1.0
7  CCC  2001-01-02     39   2.0
8  CCC  2001-01-03     40   3.0

让我们用
groupby
进行
rank
,然后

df['rank'] = df.groupby('code')['value'].rank()
df
Out[491]: 
  code        date  value  rank
0  AAA  2001-01-01     32   2.0
1  AAA  2001-01-02     23   1.0
2  AAA  2001-01-03     34   3.0
3  BBB  2001-01-01     23   2.0
4  BBB  2001-01-02     34   3.0
5  BBB  2001-01-03     12   1.0
6  CCC  2001-01-01     28   1.0
7  CCC  2001-01-02     39   2.0
8  CCC  2001-01-03     40   3.0
argsort
创造性地使用

def rank(s):
    n = len(s)
    a = s.to_numpy().argsort()
    b = np.empty_like(a)
    b[a] = np.arange(n)
    return b + 1

df.assign(rank=df.groupby('code').value.transform(rank))

  code        date  value  rank
0  AAA  2001-01-01     32     2
1  AAA  2001-01-02     23     1
2  AAA  2001-01-03     34     3
3  BBB  2001-01-01     23     2
4  BBB  2001-01-02     34     3
5  BBB  2001-01-03     12     1
6  CCC  2001-01-01     28     1
7  CCC  2001-01-02     39     2
8  CCC  2001-01-03     40     3

lexsort
unique
更具创造性,不再需要
groupby

这应该很快。我必须在更大的数据上进行测试

def rank_grouped(s, groups):
    n = len(s)
    x = s.to_numpy()
    y = groups.to_numpy()
    a = np.lexsort([x, y])
    b = np.empty_like(a)
    r = np.arange(n)

    t, i, j = np.unique(y[a], return_inverse=True, return_index=True)

    b[a] = r - i[j] + 1
    
    return b

df.assign(rank=rank_grouped(df.value, df.code))

  code        date  value  rank
0  AAA  2001-01-01     32     2
1  AAA  2001-01-02     23     1
2  AAA  2001-01-03     34     3
3  BBB  2001-01-01     23     2
4  BBB  2001-01-02     34     3
5  BBB  2001-01-03     12     1
6  CCC  2001-01-01     28     1
7  CCC  2001-01-02     39     2
8  CCC  2001-01-03     40     3

时机 大数据集

np.random.seed([3, 14])
n = 1_000_000
df = pd.DataFrame({
    'code': np.random.randint(10_000, size=n),
    'value': np.random.randn(n)
})

%timeit df.assign(rank=df.groupby('code').value.transform(rank))
%timeit df.assign(rank=df.groupby('code')['value'].rank())
%timeit df.assign(rank=rank_grouped(df.value, df.code))

1.29 s ± 7.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
367 ms ± 3.46 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
294 ms ± 2.32 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
argsort
创造性地使用

def rank(s):
    n = len(s)
    a = s.to_numpy().argsort()
    b = np.empty_like(a)
    b[a] = np.arange(n)
    return b + 1

df.assign(rank=df.groupby('code').value.transform(rank))

  code        date  value  rank
0  AAA  2001-01-01     32     2
1  AAA  2001-01-02     23     1
2  AAA  2001-01-03     34     3
3  BBB  2001-01-01     23     2
4  BBB  2001-01-02     34     3
5  BBB  2001-01-03     12     1
6  CCC  2001-01-01     28     1
7  CCC  2001-01-02     39     2
8  CCC  2001-01-03     40     3

lexsort
unique
更具创造性,不再需要
groupby

这应该很快。我必须在更大的数据上进行测试

def rank_grouped(s, groups):
    n = len(s)
    x = s.to_numpy()
    y = groups.to_numpy()
    a = np.lexsort([x, y])
    b = np.empty_like(a)
    r = np.arange(n)

    t, i, j = np.unique(y[a], return_inverse=True, return_index=True)

    b[a] = r - i[j] + 1
    
    return b

df.assign(rank=rank_grouped(df.value, df.code))

  code        date  value  rank
0  AAA  2001-01-01     32     2
1  AAA  2001-01-02     23     1
2  AAA  2001-01-03     34     3
3  BBB  2001-01-01     23     2
4  BBB  2001-01-02     34     3
5  BBB  2001-01-03     12     1
6  CCC  2001-01-01     28     1
7  CCC  2001-01-02     39     2
8  CCC  2001-01-03     40     3

时机 大数据集

np.random.seed([3, 14])
n = 1_000_000
df = pd.DataFrame({
    'code': np.random.randint(10_000, size=n),
    'value': np.random.randn(n)
})

%timeit df.assign(rank=df.groupby('code').value.transform(rank))
%timeit df.assign(rank=df.groupby('code')['value'].rank())
%timeit df.assign(rank=rank_grouped(df.value, df.code))

1.29 s ± 7.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
367 ms ± 3.46 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
294 ms ± 2.32 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

对我来说似乎是一个很好的答案(-:查看我的第二个答案。我很自豪,但必须对它进行压力测试。@piRSquared很好的解决方案,先生,第二个应该比argsort快~!明白了!也发布了时间安排。现在我只需要试着记住它。对我来说似乎是一个很好的答案(:查看我的第二个答案。我很自豪,但必须对它进行压力测试。@piRSquared很好的解决方案,先生,第二个应该比argsort快!明白了!也发布了时间安排。现在我只需要试着记住它。奖励教程打开。转换(排名)非常感谢奖励教程打开。转换(排名)非常感谢奖励教程打开