为数据框中的每一行查找 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
...
我有一个包含 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
...