为数据框中的每一行查找 n 个最低值

Finding n lowest values for each row in a dataframe

我有一个包含 1739 行和 1455 列的大型数据框。我想为每一行找到 150 个最低值(不是第 150 个值,而是 150 个值)。

我使用基本的 for 循环遍历行。

我试过 df.min(axis=1) 但它只给出了一分钟。 rolling_min 函数也没有成功。

是否有任何现有的函数可以让我输入我想要查找的值的数量 witn .min?

我的最终目标是取 150 个最低值并创建一个斜率,然后计算曲线下的面积。对每一行执行此操作并添加区域以获得体积。

数据框的示例,我有一个如下所示的 df:

     -218.7     -218.4    ...          217.2      217.5
0     56.632706  13.638315    ...      76.543000  76.543000
1     56.633455  13.576762    ...      76.543000  76.543000
2    -18.432203 -18.384091    ...      76.543000  76.543000
3    -18.476594 -18.439804    ...      76.543000  76.543000

header 是“-218.7 ...”,这是扫描的 x 轴坐标。数据是扫描 y 轴的高度。我需要的是每行的 150 个最低值和相关的列 header,因为我想为每一行制作一条曲线,然后计算曲线下的面积。

所以每一行我都需要这样的东西:

         -218.7     -218.4    ... for 150 columns
4    -18.532035 -18.497517    ... for 150 values

我认为我不需要为每一行存储 header 信息,for 循环会一次遍历每一行。

我不知道如何在不循环遍历行的情况下做到这一点:

df = df.transpose()
for col in df.columns:
    min_values = df[col].sort_values()[0:150]
    # now calc slope/area

如果我没理解错的话,问题归结为获取 M (>k) 个数字列表中的 k 个最小数字。然后将其单独应用于每一行。

如果 numpy 可用且顺序无关紧要,您可以尝试使用 argpartition:给定参数 k,它以假设第 k 个元素放入其排序位置的方式对数组进行分区,所有较小的数字在前,所有较大的数字在后(未指定顺序):

import numpy as np
row = np.array([1, 6, 2, 12, 7, 8, 9, 11, 15, 26])
k = 5
idx = np.argpartition(row, k)[:k]

print(idx)
print(row[idx])

-->
[1 0 2 4 5]
[6 1 2 7 8]

编辑:这也适用于 row/wise 全数组:

import numpy as np
data = np.array([
    [1, 6, 2, 12, 7, 8, 9, 11, 15, 26],
    [1, 65, 2, 12, 7, 8, 9, 11, 15, 26],
    [16, 6, 2, 12, 7, 8, 9, 11, 15, 26]])
k = 5
idx = np.argpartition(data, k)[:,:k]

print(idx)

-->
[[1 0 2 4 5]
 [2 0 4 5 6]
 [4 2 1 5 6]]

如果你像你在问题中提到的那样使用 for 循环遍历 df,你可以简单地这样做:

for index, row in df.iterrows(): # your loop
    new_row = sorted(row.values)[:150]
    # new_row should be a list with length 150.

测试:

import numpy
import pandas
import random

# generate dummy data
l = list(range(1600))
random.shuffle(l)
a = numpy.array(l)
a = a.reshape(40, 40) # columns x rows
dummy_df = pandas.DataFrame(a)

# dummy_df.shape = (40, 40)

smallest = []
for idx, row in dummy_df.iterrows():
    smallest.append(sorted(row.values)[:10])

new_df = pandas.DataFrame(numpy.array(smallest))
# new_df.shape = (40, 10)

您可以使用 heapq.nsmallest 在列表中找到 n 最小的数字。这可以使用 .apply:

快速应用于数据帧的每一行
import pandas as pd
import numpy as np
import heapq

df = pd.DataFrame(np.random.randn(1000, 1000))

# Find the 150 smallest values in each row
smallest = df.apply(lambda x: heapq.nsmallest(150, x), axis=1)

每行最小值现在是 df 对应行中 150 个最小值的列表。

可以使用以下方法将其转换为数据帧:

smallest_df = pd.DataFrame(smallest.values.tolist())

现在这是一个数据框,其中每一行对应于原始数据框中的每一行。有 150 列,原始数据的每一行中有 150 个最小值。

smallest_df.head()

使用.argsort 对基础数组的索引进行排序。对值和列索引进行切片以获取所需的所有信息。我们将创建一个 MultiIndex,以便我们可以将列 headers 和值存储在同一个 DataFrame 中。第一级将是您的第 n 个最低指标。

示例:

import pandas as pd
import numpy as np

np.random.seed(1)
df = pd.DataFrame(np.random.randint(1,100000, (1739, 26)))
df.columns = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ')

N = 7  # 150 in your case
idx = np.argsort(df.values, 1)[:, 0:N]

pd.concat([pd.DataFrame(np.take_along_axis(df.to_numpy(), idx, axis=1), index=df.index),
           pd.DataFrame(df.columns.to_numpy(), index=df.index)],
           keys=['Value', 'Columns'], axis=1)

输出:

      Value                                           Columns                  
          0      1      2      3      4      5      6       0  1  2  3  4  5  6
0      5193   7752   8445  19947  20610  21441  21759       C  K  U  V  I  G  P
1       432   3607  16278  17138  19434  26104  33879       R  J  W  C  B  D  G
2        16   1047   1845   9553  12314  13784  19432       K  S  E  F  M  O  U
3       244   5272  10836  13682  29237  33230  34448       K  Q  A  S  X  W  G
4      9765  11275  13160  22808  30870  33484  42760       K  T  L  U  C  D  M
5      2034   2179   4980   7184  14826  15238  22807       Z  H  F  Q  L  R  X
...