【问题标题】:Speed up turn probabilities into binary features加快将概率转化为二元特征
【发布时间】:2019-09-17 20:39:56
【问题描述】:

我有一个包含 3 列的数据框,在每一行中,我有概率在这一行中,特征 T 具有值 1、2 和 3

import pandas as pd
import numpy as np
np.random.seed(42)
df = pd.DataFrame({"T1" : [0.8,0.5,0.01],"T2":[0.1,0.2,0.89],"T3":[0.1,0.3,0.1]})

对于第 0 行,T 为 1 的概率为 80%,2 为 10%,3 为 10%

我想模拟每一行的 T 值,并将列 T1、T2、T3 更改为二进制特征。 我有一个解决方案,但它需要在数据帧的行上循环,它真的很慢(我的真实数据帧有超过 100 万行):

possib = df.columns
for i in range(df.shape[0]):
    probas = df.iloc[i][possib].tolist()
    choix_transp = np.random.choice(possib,1, p=probas)[0]
    for pos in possib:
        if pos==choix_transp:
            df.iloc[i][pos] = 1
        else:
            df.iloc[i][pos] = 0

有没有办法对这段代码进行矢量化?

谢谢!

【问题讨论】:

    标签: python pandas performance numpy vectorization


    【解决方案1】:

    这是基于vectorized random.choice with a given matrix of probabilities的一个-

    def matrixprob_to_onehot(ar):
        # Get one-hot encoded boolean array based on matrix of probabilities
        c = ar.cumsum(axis=1)
        idx = (np.random.rand(len(c), 1) < c).argmax(axis=1)
        ar_out = np.zeros(ar.shape, dtype=bool)
        ar_out[np.arange(len(idx)),idx] = 1
        return ar_out
    
    ar_out = matrixprob_to_onehot(df.values)
    df_out = pd.DataFrame(ar_out.view('i1'), index=df.index, columns=df.columns)
    

    使用大型数据集验证概率 -

    In [139]: df = pd.DataFrame({"T1" : [0.8,0.5,0.01],"T2":[0.1,0.2,0.89],"T3":[0.1,0.3,0.1]})
    
    In [140]: df
    Out[140]: 
         T1    T2   T3
    0  0.80  0.10  0.1
    1  0.50  0.20  0.3
    2  0.01  0.89  0.1
    
    In [141]: p = np.array([matrixprob_to_onehot(df.values) for i in range(100000)]).argmax(2)
    
    In [142]: np.array([np.bincount(p[:,i])/100000.0 for i in range(len(df))])
    Out[142]: 
    array([[0.80064, 0.0995 , 0.09986],
           [0.50051, 0.20113, 0.29836],
           [0.01015, 0.89045, 0.0994 ]])
    
    In [145]: np.round(_,2)
    Out[145]: 
    array([[0.8 , 0.1 , 0.1 ],
           [0.5 , 0.2 , 0.3 ],
           [0.01, 0.89, 0.1 ]])
    

    1000,000 行的计时 -

    # Setup input
    In [169]: N = 1000000
         ...: a = np.random.rand(N,3)
         ...: df = pd.DataFrame(a/a.sum(1,keepdims=1),columns=[['T1','T2','T3']])
    
    # @gmds's soln
    In [171]: %timeit pd.get_dummies((np.random.rand(len(df), 1) > df.cumsum(axis=1)).idxmin(axis=1))
    1 loop, best of 3: 4.82 s per loop
    
    # Soln from this post
    In [172]: %%timeit 
         ...: ar_out = matrixprob_to_onehot(df.values)
         ...: df_out = pd.DataFrame(ar_out.view('i1'), index=df.index, columns=df.columns)
    10 loops, best of 3: 43.1 ms per loop
    

    【讨论】:

      【解决方案2】:

      我们可以为此使用numpy

      result = pd.get_dummies((np.random.rand(len(df), 1) > df.cumsum(axis=1)).idxmin(axis=1))
      

      这会生成单列随机值并将其与数据帧的按列累积和进行比较,从而产生 DataFrame 的值,其中第一个 False 值显示随机值属于哪个“桶” . 使用idxmax,我们可以得到这个桶的索引,然后我们可以用pd.get_dummies 转换回来。

      例子:

      import numpy as np
      import pandas as pd
      
      np.random.seed(0)
      data = np.random.rand(10, 3)
      normalised = data / data.sum(axis=1)[:, np.newaxis]
      
      df = pd.DataFrame(normalised)
      result = pd.get_dummies((np.random.rand(len(df), 1) > df.cumsum(axis=1)).idxmin(axis=1))
      
      print(result)
      

      输出:

         0  1  2
      0  1  0  0
      1  0  0  1
      2  0  1  0
      3  0  1  0
      4  1  0  0
      5  0  0  1
      6  0  1  0
      7  0  1  0
      8  0  0  1
      9  0  1  0
      

      备注:

      大部分减速来自pd.get_dummies;如果使用 Divakar 的 pd.DataFrame(result.view('i1'), index=df.index, columns=df.columns) 方法,速度会快很多。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-06-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-26
        • 1970-01-01
        • 2021-07-04
        相关资源
        最近更新 更多