在数据框中为每行找到n个最小值

时间:2019-02-25 19:25:01

标签: python pandas min

我有一个大的datarframe,有1739行和1455列。我想找到每行的150个最低值(不是第150个值,而是150个值)。

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

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

是否有任何现有函数可以输入想要用.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

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

所以我需要为每一行添加以下内容:

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

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

5 个答案:

答案 0 :(得分:3)

使用.argsort获取排序的基础数组的索引。切片值和索引列以获得所需的所有信息。我们将创建一个MultiIndex,以便可以将列标题和值存储在同一DataFrame中。第一层将是您的原始索引。

示例:

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(df.values.take(idx), index=df.index),
           pd.DataFrame(df.columns[idx], index=df.index)],
           keys=['Value', 'Columns']).sort_index(level=1)

输出:

                 0      1      2      3      4      5      6
Columns 0        C      K      U      V      I      G      P
Value   0     5193   7752   8445  19947  20610  21441  21759
Columns 1        R      J      W      C      B      D      G
Value   1      432   3607  16278  17138  19434  26104  33879
Columns 2        K      S      E      F      M      O      U
Value   2       16   1047   1845   9553  12314  13784  19432
Columns 3        K      Q      A      S      X      W      G
Value   3      244   5272  10836  13682  29237  33230  34448
Columns 4        K      T      L      U      C      D      M
Value   4     9765  11275  13160  22808  30870  33484  42760
...
Columns 1736     I      L      U      W      B      X      N
Value   1736  7099   7922  11047  12613  15502  18409  21576
Columns 1737     J      K      E      V      O      M      S
Value   1737  3000   5538   7933  13777  17310  22640  24750
Columns 1738     O      U      A      X      E      I      F
Value   1738  5118   5775  10267  11320  17659  30055  30702

答案 1 :(得分:1)

如果我理解正确,那么问题就可以归结为在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]

编辑:这对于完整数组也行/明智:

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]]

答案 2 :(得分:1)

您可以使用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()

smallest_df

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

如果您使用问题中提到的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)