Pesquisa de site

Crie um modelo de aprendizado de máquina com Bash


Bash, Tcsh ou Zsh podem ajudá-lo a se preparar para o aprendizado de máquina.

O aprendizado de máquina é uma capacidade computacional poderosa para prever ou prever coisas que os algoritmos convencionais consideram desafiadoras. A jornada de aprendizado de máquina começa com a coleta e preparação de dados (muitos) e, em seguida, constrói modelos matemáticos com base nesses dados. Embora várias ferramentas possam ser usadas para essas tarefas, gosto de usar o shell.

Um shell é uma interface para realizar operações usando uma linguagem definida. Esta linguagem pode ser invocada de forma interativa ou por script. O conceito de shell foi introduzido nos sistemas operacionais Unix na década de 1970. Alguns dos shells mais populares incluem Bash, tcsh e Zsh. Eles estão disponíveis para todos os sistemas operacionais, incluindo Linux, macOS e Windows, o que lhes confere alta portabilidade. Para este exercício, usarei o Bash.

Este artigo é uma introdução ao uso de um shell para coleta e preparação de dados. Quer você seja um cientista de dados em busca de ferramentas eficientes ou um especialista em shell que deseja usar suas habilidades para aprendizado de máquina, espero que encontre informações valiosas aqui.

O exemplo de problema neste artigo é a criação de um modelo de aprendizado de máquina para prever temperaturas para os estados dos EUA. Ele usa comandos e scripts shell para executar as seguintes etapas de coleta e preparação de dados:

  1. Baixar dados
  2. Extraia os campos necessários
  3. Dados agregados
  4. Faça séries temporais
  5. Criar conjuntos de dados para treinar, testar e validar

Você pode estar se perguntando por que deveria fazer isso com shell, quando você pode fazer tudo isso em uma linguagem de programação de aprendizado de máquina como Python. Essa é uma boa pergunta. Se o processamento de dados for realizado com uma tecnologia fácil, amigável e rica como um shell, um cientista de dados se concentrará apenas na modelagem do aprendizado de máquina e não nos detalhes de uma linguagem.

Pré-requisitos

Primeiro, você precisa ter um interpretador de shell instalado. Se você usa Linux ou macOS, ele já estará instalado e você já deve estar familiarizado com ele. Se você usa Windows, experimente MinGW ou Cygwin.

Para mais informações, veja:

  • Tutoriais de Bash aqui em opensource.com
  • O tutorial oficial de script de shell de Steve Parker, o criador do Bourne Shell
  • O Guia Bash para Iniciantes do Projeto de Documentação Linux
  • Se precisar de ajuda com um comando específico, digite --help no shell para obter ajuda; por exemplo: ls --help.

iniciar

Agora que seu shell está configurado, você pode começar a preparar dados para o problema de previsão de temperatura de aprendizado de máquina.

1. Baixe dados

Os dados para este tutorial vêm da Administração Nacional Oceânica e Atmosférica dos EUA (NOAA). Você treinará seu modelo usando os dados dos últimos 10 anos completos. A fonte de dados está em https://www1.ncdc.noaa.gov/pub/data/ghcn/daily/by_year/, e os dados estão no formato .csv e compactados em gzip.

Baixe e descompacte os dados usando um script de shell. Use seu editor de texto favorito para criar um arquivo chamado download.sh e cole o código abaixo. Os comentários no código explicam o que os comandos fazem:

#!/bin/sh
# This is called hashbang. It identifies the executor used to run this file.
# In this case, the script is executed by shell itself.
# If not specified, a program to execute the script must be specified. 
# With hashbang: ./download.sh;  Without hashbang: sh ./download.sh;

FROM_YEAR=2010
TO_YEAR=2019

year=$FROM_YEAR
# For all years one by one starting from FROM_YEAR=2010 upto TO_YEAR=2019
while [ $year -le $TO_YEAR ]
do
    # show the year being downloaded now
    echo $year
    # Download
    wget https://www1.ncdc.noaa.gov/pub/data/ghcn/daily/by_year/${year}.csv.gz
    # Unzip
    gzip -d ${year}.csv.gz
    # Move to next year by incrementing
    year=$(($year+1))
done

Notas :

  • Se você estiver atrás de um servidor proxy, consulte as instruções de Mark Grennan e use:

    export http_proxy=http://username:password@proxyhost:port/
    export https_proxy=https://username:password@proxyhost:port/
  • Certifique-se de que todos os comandos padrão já estejam em seu PATH (como /bin ou /usr/bin). Caso contrário, defina seu PATH.
  • Wget é um utilitário para conectar-se a servidores web a partir da linha de comando. Se o Wget não estiver instalado em seu sistema, baixe-o.
  • Certifique-se de ter o gzip, um utilitário usado para compactação e descompactação.

Execute este script para baixar, extrair e disponibilizar dados de 10 anos como CSVs:

$ ./download.sh
2010
--2020-10-30 19:10:47--  https://www1.ncdc.noaa.gov/pub/data/ghcn/daily/by_year/2010.csv.gz
Resolving www1.ncdc.noaa.gov (www1.ncdc.noaa.gov)... 205.167.25.171, 205.167.25.172, 205.167.25.178, ...
Connecting to www1.ncdc.noaa.gov (www1.ncdc.noaa.gov)|205.167.25.171|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 170466817 (163M) [application/gzip]
Saving to: '2010.csv.gz'

     0K .......... .......... .......... .......... ..........  0% 69.4K 39m57s
    50K .......... .......... .......... .......... ..........  0%  202K 26m49s
   100K .......... .......... .......... .......... ..........  0% 1.08M 18m42s

...

O comando ls lista o conteúdo de uma pasta. Use ls 20*.csv para listar todos os seus arquivos com nomes começando com 20 e terminando com .csv.

$ ls 20*.csv
2010.csv  2011.csv  2012.csv  2013.csv  2014.csv  2015.csv  2016.csv  2017.csv  2018.csv  2019.csv

2. Extraia temperaturas médias

Extraia os dados TAVG (temperatura média) dos CSVs para regiões dos EUA:

extract_tavg_us.sh

#!/bin/sh

# For each file with name that starts with "20" and ens with ".csv"
for csv_file in `ls 20*.csv`
do
    # Message that says file name $csv_file is extracted to file TAVG_US_$csv_file
    # Example: 2010.csv extracted to TAVG_US_2010.csv
    echo "$csv_file -> TAVG_US_$csv_file"
    # grep "TAVG" $csv_file: Extract lines in file with text "TAVG"
    # |: pipe
    # grep "^US": From those extract lines that begin with text "US"
    # > TAVG_US_$csv_file: Save xtracted lines to file TAVG_US_$csv_file
    grep "TAVG" $csv_file | grep "^US" > TAVG_US_$csv_file
done

Este roteiro:

$ ./extract_tavg_us.sh
2010.csv -> TAVG_US_2010.csv
...
2019.csv -> TAVG_US_2019.csv

cria estes arquivos:

$ ls TAVG_US*.csv
TAVG_US_2010.csv  TAVG_US_2011.csv  TAVG_US_2012.csv  TAVG_US_2013.csv
TAVG_US_2014.csv  TAVG_US_2015.csv  TAVG_US_2016.csv  TAVG_US_2017.csv
TAVG_US_2018.csv  TAVG_US_2019.csv

Aqui estão as primeiras linhas de TAVG_US_2010.csv:

$ head TAVG_US_2010.csv
USR0000AALC,20100101,TAVG,-220,,,U,
USR0000AALP,20100101,TAVG,-9,,,U,
USR0000ABAN,20100101,TAVG,12,,,U,
USR0000ABCA,20100101,TAVG,16,,,U,
USR0000ABCK,20100101,TAVG,-309,,,U,
USR0000ABER,20100101,TAVG,-81,,,U,
USR0000ABEV,20100101,TAVG,-360,,,U,
USR0000ABEN,20100101,TAVG,-224,,,U,
USR0000ABNS,20100101,TAVG,89,,,U,
USR0000ABLA,20100101,TAVG,59,,,U,

O comando head é um utilitário para exibir as primeiras linhas (por padrão, 10 linhas) de um arquivo.

Os dados contêm mais informações do que você precisa. Limite o número de colunas eliminando a coluna 3 (já que todos os dados são de temperatura média) e a coluna 5 em diante. Em outras palavras, mantenha as colunas 1 (estação climática), 2 (data) e 4 (temperatura registrada).

key_columns.sh

#!/bin/sh

# For each file with name that starts with "TAVG_US_" and ens with ".csv"
for csv_file in `ls TAVG_US_*.csv`
do
    echo "Exractiing columns $csv_file"
    # cat $csv_file: 'cat' is to con'cat'enate files - here used to show one year csv file
    # |: pipe
    # cut -d',' -f1,2,4: Cut columns 1,2,4 with , delimitor
    # > $csv_file.cut: Save to temporary file
    | > $csv_file.cut: 
    cat $csv_file | cut -d',' -f1,2,4 > $csv_file.cut
    # mv $csv_file.cut $csv_file: Rename temporary file to original file
    mv $csv_file.cut $csv_file
    # File is processed and saved back into the same
    # There are other ways to do this
    # Using intermediate file is the most reliable method.
done

Execute o script:

$ ./key_columns.sh
Extracting columns TAVG_US_2010.csv
...
Extracting columns TAVG_US_2019.csv

As primeiras linhas de TAVG_US_2010.csv com os dados desnecessários removidos são:

$ head TAVG_US_2010.csv
USR0000AALC,20100101,-220
USR0000AALP,20100101,-9
USR0000ABAN,20100101,12
USR0000ABCA,20100101,16
USR0000ABCK,20100101,-309
USR0000ABER,20100101,-81
USR0000ABEV,20100101,-360
USR0000ABEN,20100101,-224
USR0000ABNS,20100101,89
USR0000ABLA,20100101,59

As datas estão em formato de string (YMD). Para treinar seu modelo corretamente, seus algoritmos precisam reconhecer campos de data no formato Y,M,D separados por vírgula (por exemplo, 20100101 se torna 2010,01,01) . Você pode convertê-los com o utilitário sed.

formato_de_data.sh

for csv_file in `ls TAVG_*.csv`
do
    echo Date formatting $csv_file
    # This inserts , after year
    sed -i 's/,..../&,/' $csv_file
    # This inserts , after month
    sed -i 's/,....,../&,/' $csv_file
done

Execute o script:

$ ./date_format.sh
Date formatting TAVG_US_2010.csv
...
Date formatting TAVG_US_2019.csv

As primeiras linhas de TAVG_US_2010.csv com o formato de data separado por vírgula são:

$ head TAVG_US_2010.csv
USR0000AALC,2010,01,01,-220
USR0000AALP,2010,01,01,-9
USR0000ABAN,2010,01,01,12
USR0000ABCA,2010,01,01,16
USR0000ABCK,2010,01,01,-309
USR0000ABER,2010,01,01,-81
USR0000ABEV,2010,01,01,-360
USR0000ABEN,2010,01,01,-224
USR0000ABNS,2010,01,01,89
USR0000ABLA,2010,01,01,59

3. Dados agregados de temperatura média dos estados

Os dados meteorológicos vêm de estações climáticas localizadas em cidades dos EUA, mas você deseja prever as temperaturas de estados inteiros. Para converter os dados das estações climáticas em dados estaduais, primeiro mapeie as estações climáticas para seus estados.

Baixe a lista de estações climáticas usando wget:

$ wget ftp://ftp.ncdc.noaa.gov/pub/data/ghcn/daily/ghcnd-stations.txt

Extraia as estações dos EUA com o utilitário grep para encontrar listagens dos EUA. O comando a seguir procura linhas que começam com o texto "US." O > é um redirecionamento que grava a saída em um arquivo — neste caso, em um arquivo chamado us_stations.txt:

$ grep "^US" ghcnd-stations.txt > us_stations.txt

Este arquivo foi criado para impressão bonita, portanto os separadores de colunas são inconsistentes:

$ head us_stations.txt
US009052008  43.7333  -96.6333  482.0 SD SIOUX FALLS (ENVIRON. CANADA)
US10RMHS145  40.5268 -105.1113 1569.1 CO RMHS 1.6 SSW
US10adam001  40.5680  -98.5069  598.0 NE JUNIATA 1.5 S
...

Torne-os consistentes usando cat para imprimir o arquivo, usando tr para comprimir repetições e gerar saída para um arquivo temporário e renomeando o arquivo temporário de volta ao original - tudo em uma linha:

$ cat us_stations.txt | tr -s ' ' > us_stations.txt.tmp; cp us_stations.txt.tmp us_stations.txt;

As primeiras linhas da saída do comando:

$ head us_stations.txt
US009052008 43.7333 -96.6333 482.0 SD SIOUX FALLS (ENVIRON. CANADA)
US10RMHS145 40.5268 -105.1113 1569.1 CO RMHS 1.6 SSW
US10adam001 40.5680 -98.5069 598.0 NE JUNIATA 1.5 S
...

Contém muitas informações – coordenadas GPS e outras coisas – mas você só precisa do código da estação e do estado. Usar corte:

$ cut -d' ' -f1,5 us_stations.txt > us_stations.txt.tmp; mv us_stations.txt.tmp us_stations.txt;

As primeiras linhas da saída do comando:

$ head us_stations.txt
US009052008 SD
US10RMHS145 CO
US10adam001 NE
US10adam002 NE
...

Transforme isso em CSV e altere os espaços para separadores de vírgula usando sed:

$ sed -i s/' '/,/g us_stations.txt

As primeiras linhas da saída do comando:

$ head us_stations.txt
US009052008,SD
US10RMHS145,CO
US10adam001,NE
US10adam002,NE
...

Embora você tenha usado vários comandos para essas tarefas, é possível executar todas as etapas de uma só vez. Tente você mesmo.

Agora, substitua os códigos de estação por seus locais de estado usando AWK, que tem funcionalidade de alto desempenho para processamento de grandes dados.

station_to_state_data.sh

#!/bin/sh

for DATA_FILE in `ls TAVG_US_*.csv`

do
    echo ${DATA_FILE}
    awk -v FILE=$DATA_FILE -F, '
        {
            state_day_sum[$1 "," $2 "," $3 "," $4] = state_day_sum[$1 "," $2 "," $3 "," $4] + $5
            state_day_num[$1 "," $2 "," $3 "," $4] = state_day_num[$1 "," $2 "," $3 "," $4] + 1
        }
        END {
            for (state_day_key in state_day_sum) {
                print state_day_key "," state_day_sum[state_day_key]/state_day_num[state_day_key]
            }
        }
    ' OFS=, $DATA_FILE > STATE_DAY_${DATA_FILE}.tmp
    sort -k1 -k2 -k3 -k4 < STATE_DAY_${DATA_FILE}.tmp > STATE_DAY_$DATA_FILE
    rm -f STATE_DAY_${DATA_FILE}.tmp
done

Aqui está o que esses parâmetros significam:

-F,

O separador de campos é ,

FNR

Número da linha em cada arquivo

NR

Número da linha em ambos os arquivos juntos

FNR==NR

É TRUE apenas no primeiro arquivo $ {PATTERN_FILE}

{ x[$1]=$2; next; }

Se FNR==NR for TRUE (somente para todas as linhas em $PATTERN_FILE)

- x

Variável para armazenar o mapa station=state

- x[$1]=$2

Adiciona dados de station=state ao mapa

- $1

Primeira coluna no primeiro arquivo (códigos de estação)

- $2

Segunda coluna no primeiro arquivo (códigos de estado)

- x

Mapa de todas as estações, por exemplo, x[US009052008]=SD, x[US10RMHS145]=CO, ..., x[USW00096409]=AK

- next

Vá para a próxima linha correspondente a FNR==NR (essencialmente, isso cria um mapa de todos os estados-estações do $ {PATTERN_FILE}

{ $1=x[$1]; print $0 }

Se FNR==NR for FALSE (somente para todas as linhas em $DATA_FILE)

- $1=x[$1]

Substitua o primeiro campo por x[$1]; essencialmente, substitua o código da estação pelo código do estado

- print $0

Imprima todas as colunas (incluindo $1 substituído)

OFS=,

O separador dos campos de saída é ,

O CSV com códigos de estação:

$ head TAVG_US_2010.csv
USR0000AALC,2010,01,01,-220
USR0000AALP,2010,01,01,-9
USR0000ABAN,2010,01,01,12
USR0000ABCA,2010,01,01,16
USR0000ABCK,2010,01,01,-309
USR0000ABER,2010,01,01,-81
USR0000ABEV,2010,01,01,-360
USR0000ABEN,2010,01,01,-224
USR0000ABNS,2010,01,01,89
USR0000ABLA,2010,01,01,59

Execute o comando:

$ ./station_to_state_data.sh
TAVG_US_2010.csv
...
TAVG_US_2019.csv

As estações agora estão mapeadas para estados:

$ head TAVG_US_2010.csv
AK,2010,01,01,-220
AZ,2010,01,01,-9
AL,2010,01,01,12
AK,2010,01,01,16
AK,2010,01,01,-309
AK,2010,01,01,-81
AK,2010,01,01,-360
AK,2010,01,01,-224
AZ,2010,01,01,59
AK,2010,01,01,-68

Cada estado tem várias leituras de temperatura para cada dia, então você precisa calcular a média das leituras de cada estado para um dia. Use AWK para processamento de texto, classifique para garantir que os resultados finais estejam em uma ordem lógica e rm para excluir o arquivo temporário após o processamento.

station_to_state_data.sh

PATTERN_FILE=us_stations.txt

for DATA_FILE in `ls TAVG_US_*.csv`
do
    echo ${DATA_FILE}

    awk -F, \
        'FNR==NR { x[$1]=$2; next; } { $1=x[$1]; print $0 }' \
        OFS=, \
        ${PATTERN_FILE} ${DATA_FILE} > ${DATA_FILE}.tmp

   mv ${DATA_FILE}.tmp ${DATA_FILE}
done

Aqui está o que os parâmetros AWK significam:

FILE=$DATA_FILE

Arquivo CSV processado como FILE

-F,

O separador de campos é ,

state_day_sum[$1 "," $2 "," $3 "," $4] = $5

state_day_sum[$1 "," $2 "," $3 "," $4] + $5

Soma da temperatura ($5) para o estado ($1) no ano ($2), mês ($3) , dia ($4)

state_day_num[$1 "," $2 "," $3 "," $4] = $5

state_day_num[$1 "," $2 "," $3 "," $4] + 1

Número de leituras de temperatura para o estado ($1) no ano ($2), mês ($3), dia ($4 código>)

END

Ao final, após coletar a soma e o número de leituras de todos os estados, anos, meses, dias, calcule as médias

for (state_day_key in state_day_sum)

Para cada estado-ano-mês-dia

print state_day_key "," state_day_sum[state_day_key]/state_day_num[state_day_key]

Imprimir estado, ano, mês, dia, média

OFS=,

O separador dos campos de saída é ,

$DATA_FILE

Arquivo de entrada (todos os arquivos com nome começando com TAVG_US_ e terminando com .csv, um por um)

> STATE_DAY_${DATA_FILE}.tmp

Salvar o resultado em um arquivo temporário

Execute o script:

$ ./TAVG_avg.sh
TAVG_US_2010.csv
TAVG_US_2011.csv
TAVG_US_2012.csv
TAVG_US_2013.csv
TAVG_US_2014.csv
TAVG_US_2015.csv
TAVG_US_2016.csv
TAVG_US_2017.csv
TAVG_US_2018.csv
TAVG_US_2019.csv

Esses arquivos são criados:

$ ls STATE_DAY_TAVG_US_20*.csv
STATE_DAY_TAVG_US_2010.csv  STATE_DAY_TAVG_US_2015.csv
STATE_DAY_TAVG_US_2011.csv  STATE_DAY_TAVG_US_2016.csv
STATE_DAY_TAVG_US_2012.csv  STATE_DAY_TAVG_US_2017.csv
STATE_DAY_TAVG_US_2013.csv  STATE_DAY_TAVG_US_2018.csv
STATE_DAY_TAVG_US_2014.csv  STATE_DAY_TAVG_US_2019.csv

Veja um ano de dados para todos os estados (menos é um utilitário para ver a saída de uma página por vez):

$ less STATE_DAY_TAVG_US_2010.csv
AK,2010,01,01,-181.934
...
AK,2010,01,31,-101.068
AK,2010,02,01,-107.11 
...
AK,2010,02,28,-138.834
...
WY,2010,01,01,-43.5625
...
WY,2010,12,31,-215.583

Mesclar todos os arquivos de dados em um:

$ cat STATE_DAY_TAVG_US_20*.csv > TAVG_US_2010-2019.csv

Agora você tem um arquivo, com todos os estados, para todos os anos:

$ cat TAVG_US_2010-2019.csv
AK,2010,01,01,-181.934
...
WY,2018,12,31,-167.421
AK,2019,01,01,-32.3386
...
WY,2019,12,30,-131.028
WY,2019,12,31,-79.8704

4. Crie dados de série temporal

Um problema como esse é adequadamente abordado com um modelo de série temporal, como a memória de longo e curto prazo (LSTM), que é uma rede neural recorrente (RNN). Esses dados de entrada são organizados em intervalos de tempo; considere 20 dias como uma fatia.

Esta é uma fatia única (como em STATE_DAY_TAVG_US_2010.csv):

X (input – 20 weeks):
AK,2010,01,01,-181.934
AK,2010,01,02,-199.531
...
AK,2010,01,20,-157.273

y (21st week, prediction for these 20 weeks):
AK,2010,01,21,-165.31

Esse intervalo de tempo é representado como (valores de temperatura em que as primeiras 20 semanas são X e 21 são y):

AK, -181.934,-199.531, ... ,
-157.273,-165.3

As fatias são contíguas no tempo. Por exemplo, o final de 2010 continua em 2011:

AK,2010,12,22,-209.92
...
AK,2010,12,31,-79.8523
AK,2011,01,01,-59.5658
...
AK,2011,01,10,-100.623

O que resulta na previsão: 

AK,2011,01,11,-106.851

Este intervalo de tempo é considerado como:

AK, -209.92, ... ,-79.8523,-59.5658, ... ,-100.623,-106.851

e assim por diante, para todos os estados, anos, meses e datas. Para obter mais explicações, consulte este tutorial sobre previsão de série temporal.

Escreva um script para criar intervalos de tempo:

timeslices.sh

#!/bin/sh

TIME_SLICE_PERIOD=20

file=TAVG_US_2010-2019.csv

# For each state in file
for state in `cut -d',' -f1 $file | sort | uniq`
do
    # Get all temperature values for the state
    state_tavgs=`grep $state $file | cut -d',' -f5`
    # How many time slices will this result in?
    # mber of temperatures recorded minus size of one timeslice
    num_slices=`echo $state_tavgs | wc -w`
    num_slices=$((${num_slices} - ${TIME_SLICE_PERIOD}))
    # Initialize
    slice_start=1; num_slice=0;
    # For each timeslice
    while [ $num_slice -lt $num_slices ]
    do
        # One timeslice is from slice_start to slice_end
        slice_end=$(($slice_start + $TIME_SLICE_PERIOD - 1))
        # X (1-20)
        sliceX="$slice_start-$slice_end"
        # y (21)
        slicey=$(($slice_end + 1))
        # Print state and timeslice temperature values (column 1-20 and 21)
        echo $state `echo $state_tavgs | cut -d' ' -f$sliceX,$slicey`
        # Increment 
        slice_start=$(($slice_start + 1)); num_slice=$(($num_slice + 1));
    done
done

Execute o script. Ele usa espaços como separadores de colunas; coloque vírgulas com sed:

$ ./timeslices.sh > TIMESLICE_TAVG_US_2010-2019.csv; sed -i s/' '/,/g TIME_VARIANT_TAVG_US_2010-2019.csv

Aqui estão as primeiras e as últimas linhas do .csv de saída:

$ head -3 TIME_VARIANT_TAVG_US_2009-2019.csv
AK,-271.271,-290.057,-300.324,-277.603,-270.36,-293.152,-292.829,-270.413,-256.674,-241.546,-217.757,-158.379,-102.585,-24.9517,-1.7973,15.9597,-5.78231,-33.932,-44.7655,-92.5694,-123.338
AK,-290.057,-300.324,-277.603,-270.36,-293.152,-292.829,-270.413,-256.674,-241.546,-217.757,-158.379,-102.585,-24.9517,-1.7973,15.9597,-5.78231,-33.932,-44.7655,-92.5694,-123.338,-130.829
AK,-300.324,-277.603,-270.36,-293.152,-292.829,-270.413,-256.674,-241.546,-217.757,-158.379,-102.585,-24.9517,-1.7973,15.9597,-5.78231,-33.932,-44.7655,-92.5694,-123.338,-130.829,-123.979

$ tail -3 TIME_VARIANT_TAVG_US_2009-2019.csv
WY,-76.9167,-66.2315,-45.1944,-27.75,-55.3426,-81.5556,-124.769,-137.556,-90.213,-54.1389,-55.9907,-30.9167,-9.59813,7.86916,-1.09259,-13.9722,-47.5648,-83.5234,-98.2963,-124.694,-142.898
WY,-66.2315,-45.1944,-27.75,-55.3426,-81.5556,-124.769,-137.556,-90.213,-54.1389,-55.9907,-30.9167,-9.59813,7.86916,-1.09259,-13.9722,-47.5648,-83.5234,-98.2963,-124.694,-142.898,-131.028
WY,-45.1944,-27.75,-55.3426,-81.5556,-124.769,-137.556,-90.213,-54.1389,-55.9907,-30.9167,-9.59813,7.86916,-1.09259,-13.9722,-47.5648,-83.5234,-98.2963,-124.694,-142.898,-131.028,-79.8704

Embora isso funcione, não tem muito desempenho. Ele pode ser otimizado – você pode tentar? Relate nos comentários abaixo como você fez isso.

5. Crie, treine, teste e valide conjuntos de dados

Divida os dados em conjuntos train, test e validate.

data_sets.sh

#!/bin/sh

GEN=SEQ
# GEN=RAN

FILE=TIMESLICE_TAVG_US_2010-2019.csv

TRAIN_SET_PERCENT=70
TEST_SET_PERCENT=20
VAL_SET_PERCENT=$(( 100 - $TRAIN_SET_PERCENT - $TEST_SET_PERCENT ))

TRAIN_DATA=TRAIN_$FILE
TEST_DATA=TEST_$FILE
VAL_DATA=VAL_$FILE

> $TRAIN_DATA
> $TEST_DATA
> $VAL_DATA

for state in `cut -d',' -f1 $FILE | sort | uniq`
do
    NUM_STATE_DATA=`grep "$state" $FILE | wc -l`
    echo "$state: $NUM_STATE_DATA"

    TRAIN_NUM_DATA=$(( $NUM_STATE_DATA * $TRAIN_SET_PERCENT / 100 ))
    TEST_NUM_DATA=$(( $NUM_STATE_DATA * $TEST_SET_PERCENT / 100 ))
    VAL_NUM_DATA=$(( $NUM_STATE_DATA - $TRAIN_NUM_DATA - $TEST_NUM_DATA ))

    if [ $GEN == "SEQ" ]
    then
        echo "Sequential"
        STATE_DATA=`grep $state $FILE`
    elif [ $GEN == "RAN" ]
    then
        echo "Randomized"
        STATE_DATA=`grep $state $FILE | shuf`
    else
        echo "Unknown data gen type: " $GEN
        exit 1
    fi

    # Train set
    per=$TRAIN_SET_PERCENT
    num=$TRAIN_NUM_DATA; from=1; to=$(($from + $num - 1));
    echo Train set: $per% $num from=$from to=$to
    echo "$STATE_DATA" | head -$to >> $TRAIN_DATA

    # Test set
    per=$TEST_SET_PERCENT
    num=$TEST_NUM_DATA; from=$(($to + 1)); to=$(($from + $num - 1));
    echo Test set: $per% $num from=$from to=$to
    echo "$STATE_DATA" | head -$to | tail -$num >> $TEST_DATA

    # Validate set
    per=$VAL_SET_PERCENT
    num=$VAL_NUM_DATA; from=$(($to + 1)); to=$NUM_STATE_DATA;
    echo Validate set: $per% $num from=$from to=$to
    echo "$STATE_DATA" | tail -$num >> $VAL_DATA

    echo
done

Isso gera conjuntos de dados que podem ser sequenciais ou aleatórios definindo GEN=SEQ ou GEN=RAN no script, e você pode embaralhar os dados com shuf.

Execute o script:

$ ./data_sets.sh
AK: 3652
Sequential
Train set: 70% 2556 from=1 to=2556
Test set: 20% 730 from=2557 to=3286
Validate set: 10% 366 from=3287 to=3652

...

WY: 3352
Sequential
Train set: 70% 2346 from=1 to=2346
Test set: 20% 670 from=2347 to=3016
Validate set: 10% 336 from=3017 to=3352

Para criar esses arquivos de dados:

$ ls *_TIMESLICE_TAVG_US_2010-2019.csv
TEST_TIMESLICE_TAVG_US_2010-2019.csv   VAL_TIMESLICE_TAVG_US_2010-2019.csv
TRAIN_TIMESLICE_TAVG_US_2010-2019.csv

Processamento de dados com shell

Quando você precisar processar uma enorme quantidade de dados para seu próximo projeto de aprendizado de máquina, pense em comandos e scripts shell. Está comprovado e pronto para uso com comunidades amigáveis para orientar e ajudar você.

Este artigo apresenta um shell para processamento de dados e os scripts demonstram oportunidades. Muito mais é possível. Você quer levar isso adiante? Conte-nos nos comentários abaixo.