【问题标题】:Finding n lowest values for each row in a dataframe为数据框中的每一行查找 n 个最小值
【发布时间】:2019-07-19 06:39:25
【问题描述】:

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

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

我试过df.min(axis=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 循环将一次遍历每一行。

【问题讨论】:

  • 你能对数组进行排序吗?如果是这样,请尝试对其进行排序,将其保存在临时数组中并获取 150 个元素的子列表
  • 只是为了澄清我自己的想法,对于所有 1739 行,您想要每行中最小的 150 个值吗?
  • @Talik 是的,如果我可以对数组进行排序,那可以工作。但随后我将不得不对其进行 1739 次排序(每行一个)。
  • 不,你只是沿第一个轴排序:np.sort(df.values, 1)[:, 0:150]
  • @d_kennetz 是的,这正是我所需要的。

标签: python pandas min


【解决方案1】:

使用.argsort 对底层数组的索引进行排序。切片值和列索引以获取您需要的所有信息。我们将创建一个 MultiIndex,以便我们可以将列标题和值存储在同一个 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
...

【讨论】:

  • @ALollz 谢谢,这很好用!我只需要找到每条曲线及其下方的区域,一切顺利!
  • 您知道如何使用 Columns 0 和 Value 0 创建曲线吗?我尝试了一个基本的 plt.scatter 但它不起作用?
  • @Mat17 我认为这足以保证new question。它可能会涉及一些groupbyMultiIndex 的切片,但这取决于您是想要所有地块还是一次只需要查看一些地块。
【解决方案2】:

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

【讨论】:

  • 如果我可以保持原始列标题链接,这将非常有效,因为它是 x 轴上的位置,而 150 个值是 y 轴上的高度。 @willk
  • 我明白了:您想要每行出现最低值的列以及值本身吗?你能举一个结束数据框的小例子吗?可能有一种方法可以修改这个答案。
  • 我在问题中添加了信息,请参见上文,感谢您的帮助。
【解决方案3】:

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

【讨论】:

  • 如果有办法让它们按顺序排列就行了,之后我需要它来构建曲线...
  • @Mat17 “按顺序排列”是什么意思? - 我认为,之后对每行 150 个条目进行排序不会有问题。如果您需要原始订单,则必须在使用前对 idx 进行排序。
【解决方案4】:

如果不遍历行,我不知道如何做到这一点:

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

【讨论】:

  • 为什么要转置df?有没有办法循环遍历行?
  • 如果需要,您可以使用:for i, row in df.iterrows() 遍历行。我认为您必须将行转换为 np.array。
【解决方案5】:

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

【讨论】:

    猜你喜欢
    • 2021-03-09
    • 1970-01-01
    • 2016-04-13
    • 2016-03-21
    • 1970-01-01
    • 1970-01-01
    • 2013-02-25
    • 1970-01-01
    相关资源
    最近更新 更多