【问题标题】:Vectorization in pandas with array inputs带有数组输入的 pandas 中的矢量化
【发布时间】:2019-12-03 12:39:05
【问题描述】:

我想以 矢量化 方式从数据框创建一个 备用矩阵,其中包含一个 标签矢量 和一个 矢量的值,同时知道所有标签

另一个限制是,我不能先创建密集数据帧,然后将其转换为备用数据帧,因为它太大而无法保存在内存中。


示例:

所有可能的标签列表:

all_labels = ['a','b','c','d','e',\
          'f','g','h','i','j',\
          'k','l','m','n','o',\
          'p','q','r','s','t',\
          'u','v','w','z']

每行带有特定标签值的数据框:

data = {'labels': [['b','a'],['q'],['n','j','v']],
        'scores': [[0.1,0.2],[0.7],[0.3,0.5,0.1]]}
df = pd.DataFrame(data)

预期的密集输出:


这就是我以非矢量化的方式完成的,这花费了太多时间:

from scipy import sparse
from scipy.sparse import coo_matrix

def labels_to_sparse(input_):
    all_, lables_, scores_ = input_
    rows = [0]*len(all_)
    cols = range(len(all_))
    vals = [0]*len(all_)
    for i in range(len(lables_)):
        vals[all_.index(lables_[i])] = scores_[i]

    return coo_matrix((vals, (rows, cols)))

df['sparse_row'] = df.apply(
        lambda x: labels_to_sparse((all_labels, x['labels'], x['scores'])), axis=1
)

df

尽管这可行,但由于必须使用df.apply,因此在处理较大数据时速度非常慢。有没有办法对这个函数进行矢量化,以避免使用apply

最后,我想用这个数据框来创建矩阵:

my_result = sparse.vstack(df['sparse_row'].values)
my_result.todense() #not really needed - just for visualization

编辑

总结公认的解决方案(@Divakar 提供):

all_labels = np.sort(all_labels)


n = len(df)
lens = list(map(len,df['labels']))
l_ar = np.concatenate(df['labels'].to_list())
d = np.concatenate(df['scores'].to_list())
R = np.repeat(np.arange(n),lens)
C = np.searchsorted(all_labels,l_ar)

my_result = coo_matrix( (d, (R, C)), shape = (n,len(all_labels)))

【问题讨论】:

    标签: python pandas vectorization sparse-matrix


    【解决方案1】:

    这是基于np.searchsorted的一个-

    n = len(df)
    lens = list(map(len,df['labels']))
    l_ar = np.concatenate(df['labels'])
    d = np.concatenate(df['scores'])
    out = np.zeros((n,len(all_labels)),dtype=d.dtype)
    R = np.repeat(np.arange(n),lens)
    C = np.searchsorted(all_labels,l_ar)
    out[R, C] = d
    

    注意:如果all_labels没有排序,我们需要使用sorter arg和searchsorted

    进入稀疏矩阵输出,如coo_matrix -

    from scipy.sparse import csr_matrix,coo_matrix
    
    out_sparse = coo_matrix( (d, (R, C)), shape = (n,len(all_labels)))
    

    【讨论】:

    • Ia 有没有办法让out 成为稀疏矩阵?如果我理解正确,out 包含结果,但它是一个 numpy 数组。另外,我必须在调用np.concatenate 之前添加.to_list()。这个问题的例子没有问题,但是对于真实的数据集(标签是单词/短语)它没有它就无法运行(KeyError:0)。
    • out_sparse 命令失败:ValueError: column index exceeds matrix dimensions。我的真实尺寸:len(all_labels) - 9933; n - 407447; len(lens) - 407447; len(l_ar) - 3018669; d.shape - (3018669,); R.shape - (3018669,); C.shape - (3018669,)
    • @matt525252 all_labels 排序了吗?
    • @matt525252 然后如帖子中所述,使用sorter arg。从这篇文章中汲取灵感 - stackoverflow.com/a/33678576
    • 当我第一次对它进行排序 (all_labels = np.sort(all_labels)) 时,您的解决方案就会起作用。它真的很快。感谢您的帮助! :)
    【解决方案2】:

    您可以尝试以下几种替代方法。

    方法 1 - 使用列表理解和 reindex 重构您的 DataFrame

    from string import ascii_lowercase
    
    all_labels = list(ascii_lowercase)
    
    my_result = (pd.DataFrame([dict(zip(l, v)) for _, (l, v) in df.iterrows()])
                 .reindex(columns=all_labels).fillna(0).values)
    

    方法 2 - for loop 使用 loc 更新值

    my_result = pd.DataFrame(np.zeros((len(df), len(all_labels))), columns=all_labels)
    
    for i, (lab, val) in df.iterrows():
        my_result.loc[i, lab] = val
    
    my_result = my_result.values
    

    两者应该产生相同的输出。

    [出]

    [[0.2 0.1 0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.
      0.  0.  0.  0.  0.  0.  0.  0. ]
     [0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.7 0.
      0.  0.  0.  0.  0.  0.  0.  0. ]
     [0.  0.  0.  0.  0.  0.  0.  0.  0.  0.5 0.  0.  0.  0.3 0.  0.  0.  0.
      0.  0.  0.  0.1 0.  0.  0.  0. ]]
    

    【讨论】:

      猜你喜欢
      • 2021-10-11
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      • 2017-02-28
      • 2021-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多