Há quase três anos, tenho registrado escrupulosamente todas as minhas receitas e despesas no hledger . Por que exatamente ele? Isso aconteceu historicamente. Com o início de 2018, comecei a escrever tudo no Google e em abril fui para o Japão. Eu estava sentado em um hotel e tentando descobrir como calcular corretamente os preços em diferentes moedas, e decidi escrever algo no Lisp. E ele escreveu . E ele mostrou para as pessoas no chat por e-mail. Ao que recebi a resposta "mas já existe um pronto" e um link para hledger. Em seguida, arrastei todas as minhas entradas do prato do google para o hledger.
O que adoro nessa forma de contabilizar despesas é a capacidade de reescrever a história. Então decidi que os fones de ouvido comprados no ano passado para minha esposa não deveriam ser escritos como "equipamento", mas como "presentes" - sem problemas.
E enquanto estudava em algum momento um cheque do Ornitorrinco, pensei, quanto eu gasto com chocolate? Spoiler - muito. Entrei no histórico de pedidos, encontrei recibos antigos lá, reescrevi as entradas por categoria. Eram apenas "despesas: alimentação", mas agora "despesas: alimentação: frutas" e outras. Ao mesmo tempo, alguns utensílios domésticos também foram encontrados lá.
A primeira vez que reescrevi completamente à mão. Ou seja, ele voltou da loja, olhou o cheque e anotou muitas linhas. Aí eu automatizei um pouco - fiz um template de prato no emacs, onde as linhas contêm produtos com suas categorias e preços, e na última coluna o filtro por categoria dá imediatamente os valores.
Mas redes neurais e outros datasatanismo.
Surgiu na minha cabeça uma ideia de que a rede neural é bastante capaz de entender que "GL.VIL.Oranges SELECT.fas.1kg" é uma fruta, ao contrário de "BOTTOM.HL.aton PODMOSKOVNY 400g" (pão, mas para isso tive que copiar este é o nome no google).
O problema a ser resolvido é obviamente a classificação. Os nomes das linhas são submetidos à entrada e uma categoria é esperada na saída. Inicialmente, vou adicionar essas categorias manualmente e, em seguida, editar apenas as previsões. Nesse sentido, o programa deve primeiro analisar o texto do cheque, selecionar os nomes dos produtos e seus preços a partir daí, prever a categoria para cada nome. Mostre-me o previsto para que eu possa corrigi-lo. Quando tudo estiver em ordem, forme um conjunto de linhas para o hledger.
, . , .
def parse_utk(lines):
while lines:
if lines[0].startswith(' '):
break
lines.pop(0)
else:
return
lines.pop(0)
result = []
while lines:
data = lines[0:6]
name, price, lines = lines[0], lines[3], lines[6:]
if name.startswith(''):
break
assert price.startswith('= ')
result.append((name, Decimal(price[2:]))
return result, . .
, . , character-level , flair. – . – . , , .
, . " ", . . . 23 21. – .
hledger.
$ hledger bal -b thisyear -% -S
100.0 % expenses:
20.6 % <unsorted>
15.3 %
7.9 %
7.1 %
6.9 %
6.3 %
5.2 %
4.8 %
4.0 %
3.8 %
2.7 %
2.7 %
2.0 %
2.0 %
1.7 %
1.6 %
1.3 %
1.2 %
0.9 %
0.9 %
0.5 %
0.4 %
0.2 % , . . , ( ) .
. , . , ?
– , . rule-based . ( - ) , ? , .
– NER. flair, ( ? ). . , IOB- … , .
rule-based , . . , "" . , . , , , . -, rule-based .
, . , . , . flair SpaceTokenizer, , . " ". , .
- - : " , , , ". , "1 107 99" , 107 99 . , ( ). ? , , .
, . . – " ", " " " ". NER . " " "".
. , (, , NewlineTokenizer), . , ColumnCorpus . \r, , . vertical tab (\x0b), RS US.
- , . , O, . , , . , , , .
, 'entry' 'entry'. – . 'O', , 'O\n', .
, . – flair.
. – , "" . .
rule-based , "" . , , rule-based . , , , rule-based .
Uma única verificação foi suficiente para treinar taggers. É verdade, primeiro tive que terminar o script para editar os resultados intermediários e depois também salvá-los no formato correto (consegui esquecer o separador de coluna especial e não entendi por uma hora porque nada funcionava). Resta apenas aparafusar a partição de "rede neural" ao analisador principal.
Em seguida, penteie o código e publique.
Fontes PS