Estou tentando concatenar todos os elementos de uma linha em uma string da seguinte maneira:
np.apply_along_axis(lambda x: " ".join(map(str, x)), 1, b)
b é
[[111,111,0,0,0], [111,111,111,111,111]]
No entanto, o resultado da linha é:
['111 111 0 0 0', '111 111 111 1']
Parece que np.apply_along_axis está cortando a segunda string para ter o mesmo comprimento da primeira. Se eu colocar uma sequência mais longa primeiro, o resultado está correto:
['111 111 111 111 111', '111 111 0 0 0']
Acho que isso é um bug?
Resumo 30/04/2019 por @seberg
np.apply_along_axis
infere o dtype de saída da primeira passagem. Que pode ser contornado, por exemplo, mas a função retornando um array de um tipo correto.
Ações:
np.apply_along_axis
poderia / deveria obter um dtype
kwarg (ou similar, compare também np.vectorize
).(encontrado isso através de # 8363) @lukovnikov - o código falha porque foi escrito com matrizes numéricas em mente, para as quais o cálculo em qualquer parte de uma matriz pode retornar o mesmo tipo de saída que qualquer outra parte. Devo observar de forma mais geral que matrizes numpy não são particularmente boas ou eficientes em strings e, a menos que você tenha uma matriz muito complicada, meu palpite é que seria muito melhor trabalhar apenas com listas e funções python, especialmente porque você já está usando as funções de string python para fazer a concatenação.
@mhvk : Discordo totalmente de sua afirmação. numpy
pode ser escrito para cálculos numéricos, mas isso não significa que omitimos a funcionalidade com str
arrays. Afinal, é por isso que temos dtypes específicos para strings, ao contrário de bibliotecas como pandas
.
Este é um bug e deve ser corrigido, a menos que você possa apresentar um argumento mais convincente do que o que você forneceu.
@gfyoung - Não estou dizendo que não se deve tentar resolver o bug (embora eu ache que é óbvio qualquer solução melhor não causar uma grande regressão de desempenho para mais típico), apenas explicando porque o bug existe e sugerindo que para strings um realmente é melhor não usar ndarray
. De qualquer forma, esses são meus 2 centavos.
@mhvk : soado como se isso não fosse realmente uma preocupação de numpy
. É por isso que eu queria enfatizar fortemente que isso é algo que devemos tentar corrigir.
Eu tive o mesmo problema:
você pode ver que corta o 'g' de jpg simplesmente referenciando-o. Achei que tem algo a ver com a mudança de forma. acabou usando listas + mapa em vez disso.
Estou assumindo que é um exemplo deliberadamente inventado, porque você não deveria usar apply_along_axis
para uma indexação simples como essa.
np.ma.apply_along_axis
funcionará corretamente aqui (por enquanto - veja # 8511). Outra opção (travou até 1.13) é uma conversão manual para dtype
object:
np.apply_along_axis(lambda x: np.array(x[0], object), 1, fnames)
@ eric-wieser, seu comentário acima me ajudou a resolver um problema que venho tendo há alguns meses com operações numpy e string. 👍
Estou assumindo que é um exemplo deliberadamente planejado, porque você não deveria usar o apply_along_axis para uma indexação simples como essa.
np.ma.apply_along_axis funcionará corretamente aqui (por enquanto - consulte # 8511). Outra opção (travou até 1.13) é uma conversão manual para o objeto dtype:
np.apply_along_axis (lambda x: np.array (x [0], objeto), 1, fnames)
Obrigado
Talvez devêssemos apenas adicionar um argumento dtype=
a apply_along_axis
@ eric-wieser
Concordo que você deve adicionar esse argumento, se houver diferenças de desempenho entre a versão do array de máscara e a versão regular. Acabei de fazer um pequeno teste (não tenho certeza se isso significa alguma coisa) e aqui está uma foto dos resultados:
Meu caso de uso : estou armazenando dados PNL analisados (strings) em matrizes numpy e tentando me livrar de todas as cláusulas for loops
e if-else
; Eu aplico algumas funções analíticas de texto usando apply_along_axis
. Qualquer benefício de velocidade seria incrível, pois cada extração de informações poderia ter de 10 a 20 variações (de um documento que poderia ter dezenas a centenas de extrações de informações que vêm de um corpus de milhares de documentos ... por dia).
Para qualquer outra pessoa que tenha esse problema com operações numpy string :
Acabei de definir explicitamente dtype
no apply_along_axis
vice normal usando a abordagem de matriz mascarada com é mais lento do que o normal apply_along_axis
.
Detalhes sobre minhas operações de string para que você possa ver se isso se aplica a você : Minha matriz numpy (definida como nump no código abaixo) tem uma forma de (26,1) e cada elemento na matriz é uma extração de informação de uma frase em um documento. Cada extração de informações é uma lista de pares de chave / valor, e estou extraindo os pares de chave / valor que representam os triplos da PNL (sujeito, relação, objeto). A função lambda
é passada pelo array para combinar o triplo em uma única sentença que testarei para a facilidade de leitura de carne kincaid, uma vez que são sentenças geradas por computador; as sentenças estavam sendo truncadas ou definidas para algum comprimento padrão com base no dtype
. O código original que estava truncando as strings era:
%timeit -n 500 np.apply_along_axis(lambda x: ("{} {} {}".format(x[0]['subject'],x[0]['relation'],x[0]['object'])),1,np.array(nump[0][0])[:,np.newaxis])
Minha velocidade era de 116 µs ± 5,42 µs por loop (média ± desvio padrão de 7 execuções, 500 loops cada)
Usando o comentário de @eric-wieser acima , costumava seguir para corrigir meu problema e manter as velocidades próximas do original:
dtype
%timeit -n 500 np.apply_along_axis(lambda x: np.array("{} {} {}".format(x[0]['subject'],x[0]['relation'],x[0]['object']),dtype='S255'),1,np.array(nump[0][0])[:,np.newaxis])
Minha velocidade era de 152 µs ± 12,6 µs por loop (média ± desvio padrão de 7 execuções, 500 loops cada)
A abordagem de matriz mascarada funciona sem alterar seu código, mas é mais lenta.
dtype
%timeit -n 500 np.ma.apply_along_axis(lambda x: ("{} {} {}".format(x[0]['subject'],x[0]['relation'],x[0]['object'])),1,np.array(nump[0][0])[:,np.newaxis])
Minha velocidade era de 925 µs ± 33,6 µs por loop (média ± desvio padrão de 7 execuções, 500 loops cada)
e tentando se livrar de todos os loops for
Observe que apply_along_axis
é apenas um loop for python, com uma pequena ajuda na alocação do array de saída para você - não é improvável que seja mais lento do que o loop que substitui
Ah, que pena; Eu estava fazendo entorpecimento porque sempre pensei que levava a velocidades mais rápidas. Sheesh.
fml
Para evitar o corte ao unir string com np.apply_along_axis:
a = np.array(['sssssssss','ffffffffffffff'])
b = np.array(['cccccccccccc','iiiiiiiiiiiiiiiii'])
def join_txt(text): return np.asarray(" ".join(text),dtype=object)
np.apply_along_axis(join_txt,0,[a,b])
o resultado é
array(['sssssssss cccccccccccc', 'ffffffffffffff iiiiiiiiiiiiiiiii'], dtype=object)
@cerlymarco , como é a abordagem que você propõe em relação à solução de @ linwoodc3 em termos de velocidade?
Talvez devêssemos apenas adicionar um argumento
dtype=
aapply_along_axis
Infelizmente, isso não é possível sem quebrar alguém. A assinatura atual é:
def apply_along_axis(func1d, axis, arr, *args, **kwargs):
Hoje, os usuários podem chamá-lo de:
def f1(x):
return x
np.apply_along_axis(f1, 0, my_arr)
def f2(x, *, dtype):
return x.astype(dtype)
np.apply_along_axis(f2, 0, my_arr, dtype=int)
Se fizermos um apply_along_axis
pegar um argumento dtype e não passá-lo para f
, então f2
falhará. Se o fizermos pegar um argumento dtype e passá-lo para f
, então f1
falhará.
O que podemos fazer é:
FutureWarning
if 'dtype' in kwargs
dizendo às pessoas para renomearem seus argumentosf2
acimaApenas um comentário que eu estava tentando adicionar um prefixo e sufixo a um nome de arquivo usando Numpy em uma série de Pandas e tive o mesmo problema (eu acho); ou seja, que a segunda corda foi cortada no mesmo comprimento que a primeira.
filenames = Series(['S1/C03/C03_R1/S1_C03_R1_PICT0239.JPG','S1/C03/C03_R1/S1_C03_R1_PICT0239.JPG'])
prefix = 'somepath'
np.char.add(prefix, filenames.astype(str))
array (['somepathS1 / C03 / C', 'somepathS1 / C03 / C'], dtype = '
Comentários muito úteis
Talvez devêssemos apenas adicionar um argumento
dtype=
aapply_along_axis