首页 > 解决方案 > 如何从条件选择的值中有效地生成百分比差异序列?

问题描述

我正在解决一个特定问题,我设法以一种非常低效的方式解决了这个问题,我想看看是否有更有效的方法来解决这个问题。我有一个数据框,它的第一列用正值填充,然后几乎 69 列用 1、0 或 -1 填充,代表某个属性的特定条件。我根据它们的位置将这些列分为 4 组,并在最后一个位置 (69) 添加了一个包含所有空值的列:

Group A = (69, 5, 6, 9, 10, 12, 15, 19, 20, 27, 43, 53, 54, 55)
Group B = (69, 6, 10, 15, 29, 31, 34, 36, 48, 49, 58, 59, 60, 62, 64, 68)
Group C = (69, 7, 13, 16, 17, 22, 24, 26, 28, 32, 33, 38, 40, 42, 44, 46, 51, 56, 66)
Group D = (69, 8, 11, 14, 18, 21, 23, 25, 30, 35, 37, 39, 41, 45, 47, 50, 52, 57, 61, 63, 65, 67)

我要做的是从每个组中随机选择 1 列,并检查所有值是 1 还是 -1,而第 69 列提供的 Null 值算作通配符,所以如果我有 1,null,1,null 算作1,1,1,1,反之亦然。

我必须生成一个系列,其中包含数据框第一列的值之间的百分比差异。第一个值将是第一行中全为 -1/null 的值,从最后一行开始的第二个值将是第一个全为 1/null 的值,这将是第一个差异,从这一行开始整个数据框选择第一个 -1/null 和随后的 1/null 来创建第二个、第三个、第四个等百分比差异,将它们添加到一个系列中。
这就是这个特定数组的样子:

Values     Column 6    Column 69    Column 28    Column 61     Selected             Perc.Diff 
  43          1           Null          1             1           43 (1st 1/null)       Nan
  90         -1           Null         -1            -1           90 (1st -1/null)      Nan
  20          1           Null          1             0           Nan                   Nan
  40         -1           Null         -1            -1           40 (2nd -1/null)      Nan 
  30          1           Null          1            -1           Nan                   Nan
  95          1           Null          1             1           95 (1st 1/Null)      0.055 (90->95)
   8          1           Null          1             1           8  (2nd 1/Null)       Nan
  52          1           Null          0             1           Nan                   Nan
  63          1           Null          1             1           63 (3rd 1/Null)       Nan 
  73         -1           Null         -1            -1           73 (1st -1/null)      Nan 
  59          1           Null          1             1           59 (1st 1/Null)     -0.274 (73->59)
  19          1           Null          0             1           Nan                   Nan
  21         -1           Null         -1            -1           21 (1st -1/null)      Nan

第一列的代码:

df = pd.DataFrame(np.random.randint(0,100,size=(100, 1)), columns=['Value'])
df1 = pd.DataFrame(np.random.randint(-1,1,size=(100, 4)), columns=['Column 6', 'Column 69', 'Column 28', 'Column 61'])
df1['Column 69'] = None
df = df.join(df1)
print(df)

最后两列不需要在数据框中,因为我只需要一个系列,其中的差异值不需要与数据框具有相同的长度。我想看看是否有更有效的方法来做到这一点。这是我的解决方案:

a = shuffle([69, 5, 6, 9, 10, 12, 15, 19, 20, 27, 43, 53, 54, 55]) 
b = shuffle([69, 5, 6, 10, 15, 29, 31, 34, 36, 48, 49, 58, 59, 60, 62, 64, 68]) 
c = shuffle([69, 7, 13, 16, 17, 22, 24, 26, 28, 32, 33, 38, 40, 42, 44, 46, 51, 56, 66])
d = shuffle([69, 8, 11, 14, 18, 21, 23, 25, 30, 35, 37, 39, 41, 45, 47, 50, 52, 57, 61, 63, 65, 67])

生成具有 4 个随机列索引的列表:

ind_list = [a[0], b[0], c[0], d[0]] 

根据选定的值创建系列:

lim = ind_list.count(69)
df.loc[(df.iloc[:, ind_list[0]] + df.iloc[:, ind_list[1]] + df.iloc[:, ind_list[2]] + df.iloc[:, 
ind_list[3]] == len(ind_list) - lim), 'Selected'] = df.Values

df.loc[(df.iloc[:, ind_list[0]] + df.iloc[:, ind_list[1]] + df.iloc[:, ind_list[2]] + df.iloc[:, 
ind_list[3]] == -len(ind_list) + lim), 'Selected'] = -df.Values

过滤不是“第一”的值:

l1 = 0
df1 = df[df['Selected'] != 0]
df1.loc[(df1.Selected.shift(1).apply(np.sign)== df1.Selected.apply(np.sign)), 
'Selected'] = 0
df2 = df1[df1['Selected'] != 0]

如果第一个值是使用 1/null 条件选择的,则删除第一个值,因为第一个元素必须是 -1/null,如果是 -1/null,则最后一个值。第 70 列是“选定”列。

if len(df2) > 0:
   if df2.iloc[0, 70] > 0: 
         l1 = 1
else:
   continue

if df2.iloc[-1, 70] < 0:
     perc = df2.iloc[l1:-1, 70].abs()
else:
     perc = df2.iloc[l1:, 70].abs()

计算百分比差异:perc_diff = perc.pct_change()[1::2]

这种方法的问题在于,我认为可以避免 if/else 块,以及这行代码的 SettingWithCopyWarning:

df1.loc[(df1.Selected.shift(1).apply(np.sign) == df1.Selected.apply(np.sign)), 'Selected'] = 0

我不知道如何避免。感谢您给我的所有帮助,因为这个脚本是一个循环的一部分,它有数千次迭代,任何毫秒我都可以保存计数。

标签: pythonpandasrandomcombinatoricsarray-difference

解决方案


推荐阅读