Mário Marroquim

Mais um blog sobre Ruby, Rails, HTML5, CSS3, Jquery...

Ruby: Introdução à Regressão Logística e Redes Neurais

Estive estudando um pouco sobre inteligência artificial para uma apresentação aqui no trabalho. Coisa básica mesmo. Quis fazer uma abordagem prática e escolhi dois assuntos para exemplificar: Regressão Logística e Redes Neurais.

Achei uma excelente gem para realizar isso, o Ai4r. Para deixar ainda mais interessante, os arquivos de entrada para treinamento da aplicação são em Excel e as saídas também. Prático para o usuário final brincar um pouco. Para trabalhar com arquivos do Excel utilizei o RubyXL.

A seguir o Gemfile do projeto:

Gemfile
1
2
3
4
5
6
source 'https://rubygems.org'

gem "ai4r"
gem "nokogiri"
gem "zip"
gem "rubyXL"

Agora o código para ler o arquivo .xlsx (passado como parâmetro), coletar os dados históricos na primeira planilha desse arquivo e inferir resultados para dados em avaliação na segunda planilha. Aqui é feita uma regressão logística com árvore de decisão e algorítimo ID3. Leia mais aqui.

logical_regression.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/ruby

require "ai4r"
require "nokogiri"
require "zip"
require "rubyXL"

excel = RubyXL::Parser.parse ARGV.first
real_lines = excel.worksheets[0].extract_data

data_set = Ai4r::Data::DataSet.new data_items: real_lines[1..(real_lines.size - 1)],
                                   data_labels: real_lines.first

id3 = Ai4r::Classifiers::ID3.new.build data_set

test_worksheet = excel.worksheets[1]

test_lines = test_worksheet.extract_data

test_lines[1..(test_lines.size - 1)].each_with_index do |columns, index|
  new_value = id3.eval(columns[0..(columns.size - 2)])
  test_worksheet[index + 1][columns.size - 1].change_contents new_value
end

excel.write ARGV.first

Em seguida está uma lógica similar, mas usando uma rede neural Perceptron, com backpropagation. Leia mais aqui.

neural_network.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/ruby

require "ai4r"
require "nokogiri"
require "zip"
require "rubyXL"

excel = RubyXL::Parser.parse ARGV.first
real_lines = excel.worksheets[0].extract_data
real_columns = real_lines.first.size - 1

net = Ai4r::NeuralNetwork::Backpropagation.new [real_columns, real_columns, 1]

(real_lines.size*100).times do
  real_lines[1..(real_lines.size - 1)].each_with_index do |columns, index|
    net.train columns[0..(columns.size - 2)].collect{|i| i.to_i}, [columns.last.to_i]
  end
end

test_worksheet = excel.worksheets[1]

test_lines = test_worksheet.extract_data

test_lines[1..(test_lines.size - 1)].each_with_index do |columns, index|
  result = net.eval(columns[0..(columns.size - 2)].collect{|i| i.to_i}).first
  test_worksheet[index + 1][columns.size - 1].change_contents result
end

excel.write ARGV.first

Baixe um arquivo Excel de exemplo aqui. Nesse exemplo, temos dados para avaliação de renovação de seguro de carros. Lembrando que da forma como estão os dois algorítimos, o Excel pode ter quantas colunas (fatores influenciadores) você quiser. Depois coloco um exemplo para predição de jogos da megasena, rsrsrsrs.

Não deixe de visitar a página do projeto no Github.

Rails: Exibindo Mensagens Flash

Exibir flashes de mensagens nas telas: sempre fiz isso de maneiras diferentes nos meus projetos Rails. Acho que nunca fui atrás de uma maneira unificada e elegante.

Nos últimos projetos com Rails 3, que em breve postarei aqui numa página específica, estive utilizando uma partial que resolveu tudo e deixou as webapps mais elegantes.

Ela se integra bem com o Twitter Bootstrap e Inherited Resources, além de ser genérica o suficiente para exibir erros dentro de qualquer @object. Ela pode ser usada também para exibir outras informações como alertas ou mensagens de sucesso :–)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<% object = (@object || resource || @resource) rescue nil -%>

<% if object.present? && object.errors.any? -%>
  <div class="alert alert-error fade in bold no-print">
    <button class="close" data-dismiss="alert">&#215;</button>
    <strong><%= t("activerecord.errors.template.body") -%></strong>
    <br/>
    <ul>
      <% object.errors.full_messages.each do |message| -%>
        <li><%= message -%></li>
      <% end -%>
    </ul>
  </div>
<% else -%>
  <% flash.each do |type, message| -%>
    <% next if ![:notice, :success, :alert, :error, :info].include? type -%>

    <div class="alert <%= bootstrap_class_for(type) -%> fade in bold no-print">
      <button class="close" data-dismiss="alert">&#215;</button>
      <%= message -%>
    </div>
  <% end -%>
<% end -%>

Tive que fazer essa checagem na linha 16 por que o Inherited Resources estava usando a funcionalidade de flash para transmitir outras informações. Aqui nos interessam apenas as mensagens ao usuário!

Bônus: o método helper bootstrap_class_for atribui a classe apropriada do Twitter Bootstrap à div da mensagem e considera até o :notice, que não era muito comum, mas agora é muito usado para enviar mensagens de sucesso ao usuário.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def bootstrap_class_for(flash_type)
  case flash_type
    when :success
      "alert-success"
    when :info
      "alert-info"
    when :error
      "alert-error"
    when :alert
      "alert-warning"
    when :notice
      "alert-success"
  else
    flash_type.to_s
  end
end

Mastering Modern Payments

Assino a excelente newsletter Ruby Weekly e me deparei com uma nova (pelo menos para mim) tecnologia para pagamento online, o Stripe.js. Achei a ideia muito interessante e com certeza vou aplicar essa ferramenta na minha próxima webapp.

Sempre utilizei o PagSeguro, da UOL, e o Mercado Pago, do Mercado Livre. Ambos são legais, mas as taxas são altas para pequenos clientes, a integração é chata e os formulários não convertem bem.

Achei esse e-book e acho que vou comprá-lo. Esse Stripe.js é muito promissor!

Javascript Best Practices

Tutorial bem legal sobre boas práticas na hora de codificar algo em Javascript. Algumas dicas servem para outras linguagens também. Leia aqui.