Skip to main content
 首页 » 编程设计

python之(Python,数据帧): Add a Column and insert the nth smallest value in the row

2025年05月04日17shihaiming

如何在 DataFrame 中找到一行中第 n 个最小的数字,并将该值添加为新列中的条目(因为我最终想导出数据)。 Example Data

请您参考如下方法:

设置

np.random.seed([3,14159]) 
 
df = pd.DataFrame(np.random.randint(10, size=(4, 5)), columns=list('ABCDE')) 
 
   A  B  C  D  E 
0  4  8  1  1  9 
1  2  8  1  4  2 
2  8  2  8  4  9 
3  4  3  4  1  5 

在以下所有解决方案中,我假设 n = 3

方案一
下面的函数 prt
使用 np.partition 将最小的放在分区的左边,最大的放在右边。然后全部向左取最大值。

df.assign(nth=np.partition(df.values, 3, axis=1)[:, :3].max(1)) 
 
   A  B  C  D  E  nth 
0  4  8  1  1  9    4 
1  2  8  1  4  2    2 
2  8  2  8  4  9    8 
3  4  3  4  1  5    4 

方案二
下面的函数 srt
使用 np.sort

更直观但成本更高的时间复杂度
df.assign(nth=np.sort(df.values, axis=1)[:, 2]) 
 
   A  B  C  D  E  nth 
0  4  8  1  1  9    4 
1  2  8  1  4  2    2 
2  8  2  8  4  9    8 
3  4  3  4  1  5    4 

方案三
下面的函数 rnk
使用 pd.DataFrame.rank
向上转换为 float 的简洁版本

df.assign(nth=df.where(df.rank(1, method='first').eq(3)).stack().values) 
 
   A  B  C  D  E  nth 
0  4  8  1  1  9  4.0 
1  2  8  1  4  2  2.0 
2  8  2  8  4  9  8.0 
3  4  3  4  1  5  4.0 

方案四
下面的函数 whr
使用 np.where 和 pd.DataFrame.rank

i, j = np.where(df.rank(1, method='first') == 3) 
df.assign(nth=df.values[i, j]) 
 
   A  B  C  D  E  nth 
0  4  8  1  1  9    4 
1  2  8  1  4  2    2 
2  8  2  8  4  9    8 
3  4  3  4  1  5    4 

时机
请注意,srt 是最快的,但与 prt 相比有一点,然后对于更多的列,更高效的 prt 算法开始发挥作用。

res.plot(loglog=True) 

prt = lambda df, n: df.assign(nth=np.partition(df.values, n, axis=1)[:, :n].max(1)) 
srt = lambda df, n: df.assign(nth=np.sort(df.values, axis=1)[:, n - 1]) 
rnk = lambda df, n: df.assign(nth=df.where(df.rank(1, method='first').eq(n)).stack().values) 
def whr(df, n): 
    i, j = np.where(df.rank(1, method='first').values == n) 
    return df.assign(nth=df.values[i, j]) 
 
res = pd.DataFrame( 
    index=[10, 30, 100, 300, 1000, 3000, 10000], 
    columns='prt srt rnk whr'.split(), 
    dtype=float 
) 
 
for i in res.index: 
    num_rows = int(np.log(i)) 
    d = pd.DataFrame(np.random.rand(num_rows, i)) 
    for j in res.columns: 
        stmt = '{}(d, 3)'.format(j) 
        setp = 'from __main__ import d, {}'.format(j) 
        res.at[i, j] = timeit(stmt, setp, number=100)