Python 字符串的快速连接

Python 字符串的快速连接,python,string,numpy,cython,Python,String,Numpy,Cython,我有一个二维0/1数组,X。每列代表一个特定的字母。对于每一行,我想连接那些在X中值为1的字母 例如: 这很好,只是这个特定任务是我代码的瓶颈。因此,我试图将其移动到cython,但没有成功,这主要是因为我对字符串和字符等方面的理解非常有限。下面的代码供参考,但它只是坏的。这一次,它没有完全返回我想要的内容(例如,字符必须转换为Python字符串),更令人担忧的是,我认为代码不稳定 import numpy as np cimport numpy as np cimport cython f

我有一个二维0/1数组,
X
。每列代表一个特定的字母。对于每一行,我想连接那些在
X
中值为1的字母

例如:

这很好,只是这个特定任务是我代码的瓶颈。因此,我试图将其移动到cython,但没有成功,这主要是因为我对字符串和字符等方面的理解非常有限。下面的代码供参考,但它只是坏的。这一次,它没有完全返回我想要的内容(例如,字符必须转换为Python字符串),更令人担忧的是,我认为代码不稳定

import numpy as np
cimport numpy as np
cimport cython 

from libc.stdlib cimport malloc, free 

def join_c(int[:,:] idx, bytes abc):

    cdef:
        size_t i, j, count
        int n = idx.shape[0]
        int m = idx.shape[1]

        char *arr = <char *>malloc((n*(m+1))*sizeof(char))

    count = 0
    try:        
        for i in range(n):
            for j in range(m):
                if idx[i,j] == 1:

                    arr[count] = abc[j]
                    count +=1 

            arr[count] = ','
            count+=1

        return [x for x in arr]

    finally:
        free(arr)   
将numpy导入为np
cimport numpy作为np
西姆波特赛顿酒店
来自libc.stdlib cimport malloc,免费
def join_c(int[:,:]idx,字节abc):
cdef:
尺寸i,j,计数
int n=idx.shape[0]
int m=idx.shape[1]
char*arr=malloc((n*(m+1))*sizeof(char))
计数=0
尝试:
对于范围(n)中的i:
对于范围内的j(m):
如果idx[i,j]==1:
arr[count]=abc[j]
计数+=1
arr[count]=','
计数+=1
返回[x代表arr中的x]
最后:
免费(arr)

我想看看如何在cython做到这一点,但我很高兴有其他快速解决方案

这里有一个基于字符串数组的解决方案-

def join_singlechars(abc, X):
    # Get mask
    mask = X==1

    # Get start, stop indices for splitting the concatenated string later on
    idx = np.r_[0,mask.sum(1).cumsum()]

    # Get concatenated string
    n = idx[-1] #sum of 1s in mask          
    s = np.broadcast_to(abc, X.shape)[mask].tostring()
    # Or np.broadcast_to(abc, X.shape)[mask].view('S'+str(n))[0]

    return [s[i:j] for i,j in zip(idx[:-1],idx[1:])] # finally split
样本运行-

In [229]: abc
Out[229]: array(['A', 'B', 'C', 'D', 'E', 'F'], dtype='|S1')

In [230]: X
Out[230]: 
array([[1, 0, 1, 0, 0, 1],
       [1, 1, 0, 1, 1, 0],
       [1, 0, 1, 1, 0, 0],
       [1, 1, 0, 1, 1, 1],
       [1, 1, 1, 0, 0, 1]])

In [231]: join_singlechars(abc, X)
Out[231]: ['ACF', 'ABDE', 'ACD', 'ABDEF', 'ABCF']
大型
5000 x 5000
阵列机箱上的计时-

In [321]: abc = np.array(['A','B','C','D','E','F'],dtype=str)
     ...: abc = np.resize(abc,5000)
     ...: np.random.seed(0)
     ...: X = np.random.randint(0,2,(5000,5000))

In [322]: %timeit [np.string_.join('',abc[row==1]) for row in X]
1 loop, best of 3: 648 ms per loop

In [323]: %timeit join_singlechars(abc, X)
1 loop, best of 3: 209 ms per loop

abc
中的所有元素都是单个字符吗?是的,它们都是英文字母表中的单个字母。您的NumPy代码将字符串与
'
连接起来。那么,为什么您尝试的Cython代码会添加
,“
字符?您想要逗号分隔字符,还是只需要连接字符?另外,最后的
[arr中x代表x]
打算做什么?如果您只想将某些内容转换为列表,请使用
list(arr)
,但为什么要在此处返回列表?你的目标是返回一个字符串,对吗?你是对的,返回值不是我想要的。
,“
用于让我知道行的起始位置。根据相应行中1的数量,每行可能具有不同数量的字符串。Nice。当增加行数时,改进变得更加显著。在我的例子中,行的数量趋向于一百万
X=np.random.randint(0,2,(1000000,abc.shape[0]))
。计时:
%timeit res=[np.string\uuu.join('',abc[row==1])对于X]1循环中的行,每个循环的最佳时间为3:2.79秒
vs.
%timeit res\u a=join\u singlechars(abc,X)1循环,每个循环的最佳时间为3:290毫秒
,我仍然很好奇在cython中如何做到这一点。@user3820991抱歉,我没有cython解决方案。
In [321]: abc = np.array(['A','B','C','D','E','F'],dtype=str)
     ...: abc = np.resize(abc,5000)
     ...: np.random.seed(0)
     ...: X = np.random.randint(0,2,(5000,5000))

In [322]: %timeit [np.string_.join('',abc[row==1]) for row in X]
1 loop, best of 3: 648 ms per loop

In [323]: %timeit join_singlechars(abc, X)
1 loop, best of 3: 209 ms per loop