为每一行计算顶部X%内有多少列

2024-06-16 13:05:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个熊猫数据框。对于每一行,我想找出变量是如何存在outlier观察的。为简单起见,假设我将异常值定义为每列中记录的值的顶部(底部)5%的观察值。你知道吗

换句话说,我想知道:

  1. 对于每列,找出记录值的最高5%(如果观察值在给定列的前5%,则返回1,否则返回0)
  2. 行总和
  3. 将标识number of outliers per row的列添加到原始数据集中

如何在python中以速度和内存效率高的方式实现这一点?你知道吗

使用R的示例:

让我们有这样的数据集:

   ID v1 v2 v3
1:  a  1  2  0
2:  b  2  3  0
3:  c  1  6  1
4:  d  3  1  2
5:  e  4  0  3
6:  f  5  2  5

# set up a reproducible example
library(data.table)
df = data.table(ID = c('a', 'b', 'c', 'd', 'e', 'f'),
                v1 = c(1,2,1,3,4,5),
                v2 = c(2,3,6,1,0,2),
                v3 = c(0,0,1,2,3,5))

# function to find out the outliers
outlier_detector = function(x, type = 'positive',tail = 0.05)
{
  if (type == 'positive')
  {
    x >= quantile(x,  1 - tail)
  }
  else if (type == 'negative')
  {
    x <= quantile(x, tail)
  }
}

# add two columns to the original dataset
# sum_out_positive - for each row calculates the number of columns where within top 5%
# sum_out_negative - for each row calculates the number of columns where within bottom 5%
df[,`:=`(
  sum_out_positive = df[,2:4][
    ,
    lapply(.SD, outlier_detector)][
      ,
      rowSums(.SD, na.rm = T),
      .SDcols = paste0('v', 1:3)],
  sum_out_negative = df[, 2:4][
    ,
    lapply(.SD, outlier_detector, 'negative')][
      ,
      rowSums(.SD, na.rm = T),
      .SDcols = paste0('v', 1:3)])]

预期产量:

   ID v1 v2 v3 sum_out_positive sum_out_negative
1:  a  1  2  0                0                2
2:  b  2  3  0                0                1
3:  c  1  6  1                1                1
4:  d  3  1  2                0                0
5:  e  4  0  3                0                1
6:  f  5  2  5                2                0

在python中实现这一点的有效方法是什么? 我知道我可以编写一个循环来迭代所有列,并根据观察值是否是异常值为每个观察值返回True/False,然后执行行求和(使用数据框总和(轴=1))。你知道吗

但是我可以不创建另一个与原始数据帧大小相同的数据帧,然后在第二步执行求和吗?i、 我想优化速度以及执行计算所需的内存量。你知道吗

奖励问题:如何改进我的R计算?你知道吗

编辑: 我想我可以用python做一些类似的事情:

(df.iloc[:, 1:3] >= df.iloc[:,1:3].quantile(0.95, axis = 0)).sum(axis = 1)

但这是最好的方法吗?你知道吗


Tags: ofthe数据idnumberdfsdout
1条回答
网友
1楼 · 发布于 2024-06-16 13:05:11

这里有一个解决方案,也许不是最优雅的方式,或者最理想的方式,但它是有效的。希望能有帮助:

# For each value column, indicate the outliers
for col in df.columns[1:]:
    df[f'{col}_outliers_pos'] = np.where(df[col] >= df[col].quantile(0.95), 1, 0)
    df[f'{col}_outliers_neg'] = np.where(df[col] <= df[col].quantile(0.05), 1, 0)

# Create lists for positive and negative columns 
pos_cols = [col for col in df.columns if 'pos' in col]
neg_cols = [col for col in df.columns if 'neg' in col]

# Calculate the sum of both negative and positive
df['sum_out_positive'] = df[pos_cols].sum(axis=1)
df['sum_out_negative'] = df[neg_cols].sum(axis=1)

# Drop columns we dont need to get correct output
df.drop(pos_cols + neg_cols, axis=1, inplace=True)

print(df)
  ID  v1  v2  v3  sum_out_positive  sum_out_negative
0  a   1   2   0                 0                 2
1  b   2   3   0                 0                 1
2  c   1   6   1                 1                 1
3  d   3   1   2                 0                 0
4  e   4   0   3                 0                 1
5  f   5   2   5                 2                 0

相关问题 更多 >