【问题标题】:selecting different columns each row每行选择不同的列
【发布时间】:2019-04-30 17:30:01
【问题描述】:

我有一个数据框,其中包含 500K 行和 7 列的天数,包括开始日和结束日。

我在 range(startDay, endDay) 中搜索一个值(比如等于 0)

比如对于 id_1,startDay=1,endDay=7,所以,我应该求一个值 D1 到 D7 列。

对于 id_2、startDay=4 和 endDay=7,因此,我应该寻找 D4 到 D7 列的值。 但是,我无法成功寻找不同的列范围。

以上,

  1. 如果 startDay > endDay,我应该看到“-999”
  2. 否则,我需要找到第一个零(考虑日期范围),例如对于 id_3,D2 列中的第一个零(第 2 天)。 id_3 的 starDay 是 1。我想看看,2-1=1 (D2 - StartDay)

  3. 如果找不到0,我想看“8”

这是我的数据;

data = {
        'D1':[0,1,1,0,1,1,0,0,0,1],
        'D2':[2,0,0,1,2,2,1,2,0,4],
        'D3':[0,0,1,0,1,1,1,0,1,0],
        'D4':[3,3,3,1,3,2,3,0,3,3],
        'D5':[0,0,3,3,4,0,4,2,3,1],
        'D6':[2,1,1,0,3,2,1,2,2,1],
        'D7':[2,3,0,0,3,1,3,2,1,3],
        'startDay':[1,4,1,1,3,3,2,2,5,2],
        'endDay':[7,7,6,7,7,7,2,1,7,6]
        }
data_idx = ['id_1','id_2','id_3','id_4','id_5',
            'id_6','id_7','id_8','id_9','id_10']
df = pd.DataFrame(data, index=data_idx)

我想看的;

df_need = pd.DataFrame([0,1,1,0,8,2,8,-999,8,1], index=data_idx)

【问题讨论】:

  • 您能解释一下为什么id_1 在df_need 中的值为1?
  • id_1 startDay=1 和 endDay=7。因此,我们应该查看 D1 到 D7 列。在 D1 = 0。这是我们的第一个 0。D1=第 1 列,startDay=1。所以,1-1=0
  • startday = 4。所以请检查您的预期输出
  • 如果 id_1 的 startDay=4,我们应该看 D4 到 D7(endDay=7) 并且第一个 0 是 D5 (range=D4 toD5)。所以,5-4=1(输出)。

标签: python-3.x pandas numpy


【解决方案1】:

您可以创建布尔数组来检查每行中的 'Dx' 列在 'startDay' 之上和 'endDay' 之下并且值等于 0。对于前两个条件,您可以使用 @987654321 @ 与 ufunc 是 np.less_equal 和 np.greater_equal 例如: 将 numpy 导入为 np

arr_bool = ( np.less_equal.outer(df.startDay, range(1,8)) # which columns Dx is above startDay
            & np.greater_equal.outer(df.endDay, range(1,8)) # which columns Dx is under endDay
            & (df.filter(regex='D[0-9]').values == 0)) #which value of the columns Dx are 0

然后您可以使用np.argmax 查找每行的第一个True。通过添加 1 并删除“startDay”,您可以获得您正在寻找的值。然后,您需要查找具有np.select 的其他条件,如果df.startDay >= df.endDay 或arr_bool 行中没有True,则将值替换为-999,例如:

df_need = pd.DataFrame( (np.argmax(arr_bool , axis=1) + 1  - df.startDay).values, 
                        index=data_idx, columns=['need'])
df_need.need= np.select( condlist = [df.startDay >= df.endDay, ~arr_bool.any(axis=1)],
                         choicelist = [ -999, 8], 
                         default = df_need.need)

print (df_need)
         need
id_1        0
id_2        1
id_3        1
id_4        0
id_5        8
id_6        2
id_7     -999
id_8     -999
id_9        8
id_10       1

注意:要为id_7 获得-999,我在np.select 中使用了条件df.startDay >= df.endDay,而不是在您的问题中使用df.startDay > df.endDay,但是您可以进行严格比较,得到8 而不是-在这种情况下为 999。

【讨论】:

  • 非常感谢!还有一个问题;如果我需要计算 startDay 和 endDay 之间的平均值,我该如何计算。 Ps:没有“.values == 0”条件。只需要每行的 D_startDay 到 D_endDay 的平均值。
  • @patronlargibi 首先从arr_bool 中删除最后一个条件& (df.filter(regex='D[0-9]').values == 0),然后执行df.filter(regex='D[0-9]').mask(~arr_bool).mean(axis=1),您应该得到开始和结束之间所有值的每行平均值。您还可以在上一个命令的末尾添加.fillna(-999) 以发现您的 startDay 大于 endDay :)
  • 感谢您的回复(:. 所以新的 arr_bool 和 df_need 应该是;new_arr_bool = ( np.less_equal.outer(df.startDay, range(1,8)) & np.greater_equal.outer(df.endDay, range(1,8)) ) 和 new_df_need = pd.DataFrame( df.filter(regex='D[0-9]').mask(~arr_bool).mean(axis=1), index=data_idx, columns=['need']) 我错了吗?
  • @patronlargibi 当您将布尔掩码重命名为 new_arr_bool 时,您应该在掩码中使用这个,例如 ...mask(~new_arr_bool)...
猜你喜欢
  • 2012-10-20
  • 2012-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-09
  • 2017-07-24
相关资源
最近更新 更多