Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> การเขียนโปรแกรม Bash

สร้างโมเดล Machine Learning ด้วย Bash Scripts

บทนำ

Machine learning เป็นความสามารถคอมพิวติ้งที่ทรงพลังสำหรับการพยากรณ์หรือ forecasting สิ่งต่างๆ ที่ conventional algorithms พบว่าท้าทาย การเดินทางของ machine learning เริ่มต้นด้วยการเก็บและเตรียมข้อมูล — เยอะมาก — แล้วสร้าง mathematical models จากข้อมูลนั้น แม้จะมีหลายเครื่องมือสำหรับงานเหล่านี้ ผมชอบใช้ shell

Shell เป็นอินเทอร์เฟซสำหรับดำเนินการโดยใช้ภาษาที่กำหนด ภาษานี้สามารถเรียกใช้แบบ interactive หรือ scripted แนวคิด shell ถูกนำเสนอใน Unix operating systems ในทศวรรษ 1970 Shells ยอดนิยมรวมถึง Bash, tcsh, และ Zsh พวกมันพร้อมสำหรับทุกระบบปฏิบัติการ รวมถึง Linux, macOS, และ Windows ทำให้มี portability สูง สำหรับแบบฝึกหัดนี้ ผมจะใช้ Bash

บทความนี้เป็นการแนะนำการใช้ shell สำหรับการเก็บข้อมูลและเตรียมข้อมูล ไม่ว่าคุณจะเป็น data scientist ที่มองหาเครื่องมือที่มีประสิทธิภาพ หรือ shell expert ที่มองใช้ทักษะสำหรับ machine learning ผมหวังว่าคุณจะพบข้อมูลที่มีค่า

ปัญหาตัวอย่างในบทความนี้คือการสร้าง machine learning model เพื่อพยากรณ์อุณหภูมิของรัฐใน US ใช้ shell commands และ scripts ทำขั้นตอนการเก็บและเตรียมข้อมูลต่อไปนี้:

  1. ดาวน์โหลดข้อมูล
  2. แยกฟิลด์ที่จำเป็น
  3. รวมข้อมูล (Aggregate)
  4. สร้าง time series
  5. สร้าง train, test, และ validate data sets

คุณอาจถามว่าทำไมต้องทำด้วย shell ถ้าทำได้หมดใน machine learning programming language อย่าง Python คำถามที่ดี หาก data processing ทำด้วยเทคโนโลยีที่ง่าย เรียบง่าย และรวย เช่น shell data scientist จะโฟกัสแค่ machine learning modeling ไม่ใช่รายละเอียดของภาษา

ข้อกำหนดเบื้องต้น

ก่อนอื่น คุณต้องมี shell interpreter ติดตั้ง หากคุณใช้ Linux หรือ macOS มันจะติดตั้งอยู่แล้ว และคุณอาจคุ้นเคยแล้ว หากใช้ Windows ลอง MinGW หรือ Cygwin

สำหรับข้อมูลเพิ่มเติม ดู:

  • Bash tutorials บน opensource.com
  • Official shell scripting tutorial โดย Steve Parker ผู้สร้าง Bourne shell
  • The Bash Guide for Beginners โดย Linux Documentation Project
  • หากต้องการช่วยเหลือคำสั่งเฉพาะ พิมพ์ <commandname> --help ใน shell เช่น ls --help

เริ่มต้น

ตอนนี้ shell ของคุณพร้อมแล้ว คุณสามารถเริ่มเตรียมข้อมูลสำหรับปัญหา machine learning พยากรณ์อุณหภูมิ

1. ดาวน์โหลดข้อมูล

ข้อมูลสำหรับ tutorial นี้มาจาก US National Oceanic and Atmospheric Administration (NOAA) คุณจะ train model ด้วยข้อมูล 10 ปีเต็มล่าสุด Data source อยู่ที่ https://www1.ncdc.noaa.gov/pub/data/ghcn/daily/by_year/ และข้อมูลเป็นรูปแบบ .csv และ gzipped

ดาวน์โหลดและ unzip ข้อมูลด้วย shell script ใช้ text editor โปรดสร้างไฟล์ชื่อ download.sh และวางโค้ดด้านล่าง คอมเมนต์ในโค้ดอธิบายว่าคำสั่งทำอะไร:

#!/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

Notes:

  • หากคุณอยู่หลัง proxy server โปรดดู how-to ของ Mark Grennan และใช้:
    export http_proxy=https://username:password@proxyhost:port/
    export https_proxy=https://username:password@proxyhost:port/
  • ตรวจสอบว่า standard commands ทั้งหมดอยู่ใน PATH แล้ว (เช่น /bin หรือ /usr/bin) หากไม่ได้ ตั้ง PATH
  • Wget เป็น utility สำหรับเชื่อมต่อ web servers จากบรรทัดคำสั่ง หาก Wget ไม่ได้ติดตั้ง ดาวน์โหลดมัน
  • ตรวจสอบว่ามี gzip utility สำหรับ compression และ decompression

รันสคริปต์นี้เพื่อดาวน์โหลด แยกไฟล์ และทำให้ข้อมูล 10 ปีพร้อมเป็น 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
...

คำสั่ง ls แสดงเนื้อหาโฟลเดอร์ ใช้ ls 20*.csv เพื่อแสดงไฟล์ทั้งหมดที่ชื่อขึ้นต้นด้วย 20 และลงท้ายด้วย .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. แยกอุณหภูมิเฉลี่ย

แยกข้อมูล TAVG (average temperature) จาก CSVs สำหรับภูมิภาค US:

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

สคริปต์นี้สร้างไฟล์เหล่านี้:

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

$ 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

นี่คือบรรทัดแรกๆ สำหรับ 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,

คำสั่ง head เป็น utility สำหรับแสดงบรรทัดแรกๆ (โดยค่าเริ่มต้น 10 บรรทัด) ของไฟล์

ข้อมูลมีข้อมูลมากกว่าที่คุณต้องการ จำกัดจำนวนคอลัมน์โดยกำจัดคอลัมน์ 3 (เพราะข้อมูลทั้งหมดคือ average temperature) และคอลัมน์ 5 เป็นต้นไป กล่าวคือ เก็บคอลัมน์ 1 (climate station), 2 (date), และ 4 (อุณหภูมิที่บันทึก)

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

รันสคริปต์:

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

บรรทัดแรกๆ ของ TAVG_US_2010.csv ที่ลบข้อมูลไม่จำเป็นแล้ว:

$ 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

วันที่อยู่ในรูปแบบ string (YMD) เพื่อ train model ให้ถูกต้อง algorithms ของคุณต้องรู้จัก date fields ในรูปแบบ Y,M,D คั่นด้วย comma (เช่น 20100101 กลายเป็น 2010,01,01) คุณแปลงได้ด้วย sed utility

date_format.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

รันสคริปต์:

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

บรรทัดแรกๆ ของ TAVG_US_2010.csv พร้อมรูปแบบวันที่คั่นคอมมา:

$ 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. รวมข้อมูลอุณหภูมิเฉลี่ยของรัฐ

ข้อมูลสภาพอากาศมาจาก climate stations ในเมือง US แต่คุณต้องการพยากรณ์อุณหภูมิของทั้งรัฐ ในการแปลงข้อมูล climate-station เป็นข้อมูลรัฐ แรกเริ่ม map climate stations ไปยังรัฐของพวกมัน

ดาวน์โหลดรายชื่อ climate stations ด้วย wget:

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

แยก US stations ด้วย grep utility เพื่อหา US listings คำสั่งต่อไปนี้ค้นหาบรรทัดที่ขึ้นต้นด้วยข้อความ "US > เป็น redirection ที่เขียน output ไปไฟล์ — ในกรณีนี้ ไฟล์ชื่อ us_stations.txt:

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

ไฟล์นี้สร้างสำหรับ pretty print ดังนั้น column separators ไม่สม่ำเสมอ:

$ 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
...

ทำให้สม่ำเสมอโดยใช้ cat พิมพ์ไฟล์ ใช้ tr squeeze repeats และ output ไป temp file และ rename temp file กลับเป็น original — ทั้งหมดในบรรทัดเดียว:

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

บรรทัดแรกของ output คำสั่ง:

$ 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
...

มีข้อมูลมาก — GPS coordinates และอื่นๆ — แต่คุณต้องการแค่ station code และ state ใช้ cut:

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

บรรทัดแรกของ output คำสั่ง:

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

ทำให้เป็น CSV และเปลี่ยน space เป็น comma separators ด้วย sed:

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

บรรทัดแรกของ output คำสั่ง:

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

แม้คุณจะใช้คำสั่งหลายตัวสำหรับงานเหล่านี้ แต่มันเป็นไปได้ที่จะทำทุกขั้นตอนใน one run ลองทำเองดู

ตอนนี้ แทนที่ station codes ด้วย state locations โดยใช้ AWK ซึ่งมีประสิทธิภาพสูงสำหรับ large data processing

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

นี่คือความหมายของพารามิเตอร์เหล่านี้:

-F,Field separator คือ ,
FNRLine number ในแต่ละไฟล์
NRLine number ในทั้งสองไฟล์รวมกัน
FNR==NRเป็น TRUE เฉพาะในไฟล์แรก ${PATTERN_FILE}
{ x[$1]=$2; next; }ถ้า FNR==NR เป็น TRUE (สำหรับทุกบรรทัดใน $PATTERN_FILE เท่านั้น)
- xVariable เก็บ map station=state
- x[$1]=$2เพิ่มข้อมูล station=state ลง map
- $1คอลัมน์แรกในไฟล์แรก (station codes)
- $2คอลัมน์ที่สองในไฟล์แรก (state codes)
- xMap ของทุก stations เช่น x[US009052008]=SD, x[US10RMHS145]=CO, ..., x[USW00096409]=AK
- nextไปบรรทัดถัดไปที่ match FNR==NR (โดยสรุป สร้าง map ของ stations-states ทั้งหมดจาก ${PATTERN_FILE}
{ $1=x[$1]; print $0 }ถ้า FNR==NR เป็น FALSE (สำหรับทุกบรรทัด in $DATA_FILE เท่านั้น)
- $1=x[$1]แทนที่ฟิลด์แรกด้วย x[$1]; กล่าวคือ แทนที่ station code ด้วย state code
- print $0พิมพ์ทุกคอลัมน์ (รวม $1 ที่แทนที่แล้ว)
OFS=,Output fields separator คือ ,

CSV ที่มี station codes:

$ 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

รันคำสั่ง:

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

Stations ตอนนี้ mapped ไป states แล้ว:

$ 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

ทุกรัฐมีอ่านค่าอุณหภูมิหลายค่าต่อวัน ดังนั้นคุณต้องคำนวณค่าเฉลี่ยของแต่ละรัฐแต่ละวัน ใช้ AWK สำหรับ text processing, sort เพื่อให้ผลลัพธ์สุดท้ายเรียงลำดับสมเหตุสมผล และ rm เพื่อลบ temporary file หลังประมวลผล

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

นี่คือความหมายของ AWK parameters:

FILE=$DATA_FILECSV file processed as FILE
-F,Field separator คือ ,
state_day_sum[$1 "," $2 "," $3 "," $4] = $5

state_day_sum[$1 "," $2 "," $3 "," $4] + $5
Sum of temperature ($5) for the state ($1) on year ($2), month ($3), day ($4)
state_day_num[$1 "," $2 "," $3 "," $4] = $5

state_day_num[$1 "," $2 "," $3 "," $4] + 1
Number of temperature readings for the state ($1) on year ($2), month ($3), day ($4)
ENDในท้ายที่สุด หลังจากรวบรวม sum และจำนวน readings สำหรับทุกรัฐ ปี เดือน วัน คำนวณ averages
for (state_day_key in state_day_sum)สำหรับแต่ละ state-year-month-day
print state_day_key "," state_day_sum[state_day_key]/state_day_num[state_day_key]พิมพ์ state,year,month,day,average
OFS=,Output fields separator คือ ,
$DATA_FILEInput file (all files with name starting with TAVG_US_ and ending with .csv, one by one)
> STATE_DAY_${DATA_FILE}.tmpSave result to a temporary file

รันสคริปต์:

$ ./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

ไฟล์เหล่านี้ถูกสร้าง:

$ 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

ดูข้อมูลหนึ่งปีสำหรับทุกรัฐ (less คือ utility ดู output ทีละหน้า):

$ 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

รวมไฟล์ข้อมูลทั้งหมดเป็นไฟล์เดียว:

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

ตอนนี้คุณมีไฟล์เดียว พร้อมทุกรัฐ สำหรับทุกปี:

$ 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. สร้างข้อมูล Time-series

ปัญหาแบบนี้เหมาะกับ time-series model อย่าง long short-term memory (LSTM) ซึ่งเป็น recurring neural network (RNN) Input data จัดเป็น time slices พิจารณา 20 วันเป็นหนึ่ง slice

นี่คือ one-time slice (จาก 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

Time slice นี้แสดงเป็น (ค่าอุณหภูมิที่ 20 สัปดาห์แรกคือ X, และ 21 คือ y):

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

Slices เป็น time-contiguous ตัวอย่าง สิ้นสุด 2010 ต่อเนื่องเข้าสู่ 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

ซึ่งให้ prediction:

AK,2011,01,11,-106.851

Time slice นี้ถูกนำเป็น:

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

และต่อเนื่องไป สำหรับทุกรัฐ ปี เดือน และวันที่ สำหรับคำอธิบายเพิ่มเติม ดู tutorial on time-series forecasting

เขียนสคริปต์สร้าง time slices:

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

รันสคริปต์ มันใช้ space เป็น column separators ทำให้เป็น comma ด้วย sed:

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

นี่คือบรรทัดแรกๆ และบรรทัดสุดท้ายของ output .csv:

$ 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

แม้จะทำงานได้ แต่มันไม่ค่อย performant สามารถ optimize ได้ — คุณลองดูได้ไหม รายงานในความคิดเห็นด้านล่างว่าคุณทำอย่างไร

5. สร้าง train, test, และ validate data sets

แยกข้อมูลเป็น train, test, และ validate sets

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

สคริปต์นี้สร้าง data sets ที่เป็น sequential หรือ randomized โดยตั้ง GEN=SEQ หรือ GEN=RAN ในสคริปต์ และคุณสามารถ shuffle data ด้วย shuf

รันสคริปต์:

$ ./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

เพื่อสร้างไฟล์ข้อมูลเหล่านี้:

$ 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

การประมวลผลข้อมูลด้วย Shell

เมื่อคุณต้องประมวลผลข้อมูลจำนวนมหาศาลสำหรับ machine learning project ถัดไป ลองคิดถึง shell commands และ scripts มันพิสูจน์แล้วและพร้อมใช้งานพร้อมชุมชนที่เป็นมิตรช่วยเหลือและนำทางคุณ

บทความนี้แนะนำ shell สำหรับ data processing และสคริปต์สาธิตโอกาส มากกว่านี้ก็ทำได้อีกมาก อยากพัฒนาต่อไหม? บอกเราในความคิดเห็นด้านล่าง