代码之家  ›  专栏  ›  技术社区  ›  Christopher

数组中的条件选择

  •  2
  • Christopher  · 技术社区  · 7 年前

    我有以下数组列表:

    [array([10,  1,  7,  3]),
     array([ 0, 14, 12, 13]),
     array([ 3, 10,  7,  8]),
     array([7, 5]),
     array([ 5, 12,  3]),
     array([14,  8, 10])]
    

    我想要的是将行标记为“1”或“0”,这取决于行是否匹配“10”和“7”或“10”和“3”。

    np.where(output== 10 & output == 7 ) | (output == 10 & output == 3 ) | (output == 10 & output == 8 ), 1, 0)
    

    回报

    array(0)
    

    进入数组数组的正确语法是什么?

    预期产量:

    [ 1, 0, 1, 0, 0, 1 ]
    

    注: 是什么 output ? 在Scikit中训练CountVectorizer/LDA主题分类器之后,下面的脚本为新文档分配主题概率。高于阈值0.2的主题将存储在数组中。

    def sortthreshold(x, thresh):
        idx = np.arange(x.size)[x > thresh]
        return idx[np.argsort(x[idx])]
    
    output = []
    for x in newdoc:
        y = lda.transform(bowvectorizer.transform([x]))
        output.append(sortthreshold(y[0], 0.2))
    

    谢谢!

    2 回复  |  直到 7 年前
        1
  •  1
  •   Reblochon Masque    7 年前

    你需要使用 np.any 结合 np.where ,并避免使用 | & 它们是python中的二进制运算符。

    import numpy as np
    
    a = [np.array([10,  1,  7,  3]),
         np.array([ 0, 14, 12, 13]),
         np.array([ 3, 10,  7,  8]),
         np.array([7, 5]),
         np.array([ 5, 12,  3]),
         np.array([14,  8, 10])]
    
    for output in a:
        print(np.where(((any(output == 10) and any(output == 7))) or 
                       (any(output == 10) and any(output == 3)) or
                       (any(output == 10) and any(output == 8 )), 1, 0))
    

    输出:

    1
    0
    1
    0
    0
    1
    

    如果您希望将其作为列表,如编辑后的问题所示:

    result = []
    for output in a:
        result.append(1 if np.where(((any(output == 10) and any(output == 7))) or 
                       (any(output == 10) and any(output == 3)) or
                       (any(output == 10) and any(output == 8 )), 1, 0) == True else 0)
    
    result
    

    结果:

    [1, 0, 1, 0, 0, 1]
    
        2
  •  2
  •   PM 2Ring    7 年前

    您的输入数据是一个长度不等的Numpy数组的纯Python列表,因此它不能简单地转换为2D Numpy数组,也不能由Numpy直接处理。但它可以使用常用的Python列表处理工具进行处理。

    下面是一个列表理解,它使用 numpy.isin 测试一行是否包含(3,7,8)中的任何一个。我们先用简单的 == 测试该行是否包含10,并且只调用 isin 如果它这样做了;巨蟒 and 如果第一个操作数为false ish,则运算符将不计算其第二个操作数。

    我们用 np.any 查看是否有行项目通过每个测试。 np.任何 返回布尔值 False True ,但我们可以将这些值传递给 int 将它们转换为0或1。

    import numpy as np
    
    data = [
        np.array([10, 1, 7, 3]), np.array([0, 14, 12, 13]),
        np.array([3, 10, 7, 8]), np.array([7, 5]),
        np.array([5, 12, 3]), np.array([14, 8, 10]),
    ]
    
    mask = np.array([3, 7, 8])
    result = [int(np.any(row==10) and np.any(np.isin(row, mask)))
        for row in data]
    
    print(result)
    

    输出

    [1, 0, 1, 0, 0, 1] 
    

    我刚表演了一些 timeit 测验。奇怪的是,Reblochon Masque的代码在问题中给出的数据上运行得更快,可能是因为普通Python的短路行为 any , &安培; or . 而且,看起来 numpy.in1d 努比·伊辛 ,即使文档建议在新代码中使用后者。

    这是一个新版本,比雷博龙慢10%左右。

    mask = np.array([3, 7, 8])
    result = [int(any(row==10) and any(np.in1d(row, mask)))
        for row in data]
    

    当然,大量真实数据的真实速度可能与我的测试结果有所不同。时间可能不是问题:即使在我那台32位单核2GHz的老机器上,我也能在一秒钟内处理问题中的数据近3000次。


    hpaulj提出了一个更快的方法。这里有些 timeit test 信息,比较不同的版本。这些测试是在我的旧机器YMMV上进行的。

    import numpy as np
    from timeit import Timer
    
    the_data = [
        np.array([10, 1, 7, 3]), np.array([0, 14, 12, 13]),
        np.array([3, 10, 7, 8]), np.array([7, 5]),
        np.array([5, 12, 3]), np.array([14, 8, 10]),
    ]
    
    def rebloch0(data):
        result = []
        for output in data:
            result.append(1 if np.where((any(output == 10) and any(output == 7)) or
                (any(output == 10) and any(output == 3)) or
                (any(output == 10) and any(output == 8)), 1, 0) == True else 0)
        return result
    
    def rebloch1(data):
        result = []
        for output in data:
            result.append(1 if np.where((any(output == 10) and any(output == 7)) or
                (any(output == 10) and any(output == 3)) or
                (any(output == 10) and any(output == 8)), 1, 0) else 0)
        return result
    
    def pm2r0(data):
        mask = np.array([3, 7, 8])
        return [int(np.any(row==10) and np.any(np.isin(row, mask)))
            for row in data]
    
    def pm2r1(data):
        mask = np.array([3, 7, 8])
        return [int(any(row==10) and any(np.in1d(row, mask)))
            for row in data]
    
    def hpaulj0(data):
        mask=np.array([3, 7, 8])
        return [int(any(row==10) and any((row[:, None]==mask).flat))
            for row in data]
    
    def hpaulj1(data, mask=np.array([3, 7, 8])):
        return [int(any(row==10) and any((row[:, None]==mask).flat))
            for row in data]
    
    functions = (
        rebloch0,
        rebloch1,
        pm2r0,
        pm2r1,
        hpaulj0,
        hpaulj1,
    )
    
    # Verify that all functions give the same result
    for func in functions:
        print('{:8}: {}'.format(func.__name__, func(the_data)))
    print()
    
    def time_test(loops, data):
        timings = []
        for func in functions:
            t = Timer(lambda: func(data))
            result = sorted(t.repeat(3, loops))
            timings.append((result, func.__name__))
        timings.sort()
        for result, name in timings:
            print('{:8}: {:.6f}, {:.6f}, {:.6f}'.format(name, *result))
        print()
    
    time_test(1000, the_data)
    

    典型输出

    rebloch0: [1, 0, 1, 0, 0, 1]
    rebloch1: [1, 0, 1, 0, 0, 1]
    pm2r0   : [1, 0, 1, 0, 0, 1]
    pm2r1   : [1, 0, 1, 0, 0, 1]
    hpaulj0 : [1, 0, 1, 0, 0, 1]
    hpaulj1 : [1, 0, 1, 0, 0, 1]
    
    hpaulj1 : 0.140421, 0.154910, 0.156105
    hpaulj0 : 0.154224, 0.154822, 0.167101
    rebloch1: 0.281700, 0.282764, 0.284599
    rebloch0: 0.339693, 0.359127, 0.375715
    pm2r1   : 0.367677, 0.368826, 0.371599
    pm2r0   : 0.626043, 0.628232, 0.670199
    

    干得好,帕瑞!