Máy học là một khả năng tính toán mạnh mẽ để dự đoán hoặc dự báo những điều mà các thuật toán thông thường thấy khó khăn. Hành trình học máy bắt đầu với việc thu thập và chuẩn bị dữ liệu — một lô của nó — sau đó nó xây dựng các mô hình toán học dựa trên dữ liệu đó. Mặc dù có thể sử dụng nhiều công cụ cho những tác vụ này, nhưng tôi thích sử dụng shell.
Một trình bao là một giao diện để thực hiện các hoạt động sử dụng một ngôn ngữ xác định. Ngôn ngữ này có thể được gọi tương tác hoặc theo tập lệnh. Khái niệm shell được giới thiệu trong hệ điều hành Unix vào những năm 1970. Một số shell phổ biến nhất bao gồm Bash, tcsh và Zsh. Chúng có sẵn cho tất cả các hệ điều hành, bao gồm Linux, macOS và Windows, mang lại cho chúng tính di động cao. Đối với bài tập này, tôi sẽ sử dụng Bash.
Bài viết này giới thiệu cách sử dụng shell để thu thập dữ liệu và chuẩn bị dữ liệu. Cho dù bạn là một nhà khoa học dữ liệu đang tìm kiếm các công cụ hiệu quả hay một chuyên gia trình bao đang tìm cách sử dụng các kỹ năng của bạn để học máy, tôi hy vọng bạn sẽ tìm thấy thông tin có giá trị ở đây.
Vấn đề ví dụ trong bài viết này là tạo ra một mô hình học máy để dự báo nhiệt độ cho các bang của Hoa Kỳ. Nó sử dụng các lệnh và tập lệnh shell để thực hiện các bước thu thập dữ liệu và chuẩn bị dữ liệu sau:
- Tải xuống dữ liệu
- Trích xuất các trường cần thiết
- Dữ liệu tổng hợp
- Tạo chuỗi thời gian
- Tạo tập, kiểm tra và xác thực các tập dữ liệu
Bạn có thể hỏi tại sao bạn nên làm điều này với shell, khi bạn có thể thực hiện tất cả bằng ngôn ngữ lập trình học máy như Python. Đây là một câu hỏi hay. Nếu việc xử lý dữ liệu được thực hiện bằng một công nghệ dễ dàng, thân thiện và phong phú như shell, thì nhà khoa học dữ liệu chỉ tập trung vào mô hình học máy chứ không phải chi tiết của một ngôn ngữ.
Điều kiện tiên quyết
Đầu tiên, bạn cần phải cài đặt trình thông dịch shell. Nếu bạn sử dụng Linux hoặc macOS, nó sẽ được cài đặt sẵn và bạn có thể đã quen với nó. Nếu bạn sử dụng Windows, hãy thử MinGW hoặc Cygwin.
Để biết thêm thông tin, hãy xem:
- Các bài hướng dẫn về Bash tại đây trên opensource.com
- Hướng dẫn viết kịch bản shell chính thức của Steve Parker, tác giả của Bourne shell
- Hướng dẫn Bash cho người mới bắt đầu của Dự án Tài liệu Linux
- Nếu bạn cần trợ giúp với một lệnh cụ thể, hãy nhập
<commandname> --help
trong vỏ để được giúp đỡ; ví dụ:ls --help
.
Bắt đầu
Bây giờ shell của bạn đã được thiết lập, bạn có thể bắt đầu chuẩn bị dữ liệu cho bài toán dự đoán nhiệt độ của máy học.
1. Tải xuống dữ liệu
Dữ liệu cho hướng dẫn này đến từ Cơ quan Khí quyển và Đại dương Quốc gia Hoa Kỳ (NOAA). Bạn sẽ đào tạo mô hình của mình bằng cách sử dụng dữ liệu hoàn chỉnh của 10 năm qua. Nguồn dữ liệu tại https://www1.ncdc.noaa.gov/pub/data/ghcn/daily/by_year/ và dữ liệu ở định dạng .csv và được nén.
Tải xuống và giải nén dữ liệu bằng tập lệnh shell. Sử dụng trình soạn thảo văn bản yêu thích của bạn để tạo tệp có tên download.sh
và dán mã bên dưới. Các nhận xét trong mã giải thích chức năng của các lệnh:
#!/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
Ghi chú:
- Nếu bạn đang sử dụng máy chủ proxy, hãy tham khảo cách thực hiện của Mark Grennan và sử dụng:
export http_proxy=https://username:password@proxyhost:port/
export https_proxy=https://username:password@proxyhost:port/ - Đảm bảo rằng tất cả các lệnh chuẩn đã có trong PATH của bạn (chẳng hạn như
/bin
hoặc/usr/bin
). Nếu không, hãy đặt PATH của bạn. - Wget là một tiện ích để kết nối với các máy chủ web từ dòng lệnh. Nếu Wget chưa được cài đặt trên hệ thống của bạn, hãy tải xuống.
- Đảm bảo bạn có gzip, một tiện ích dùng để nén và giải nén.
Chạy tập lệnh này để tải xuống, trích xuất và cung cấp dữ liệu có giá trị 10 năm dưới dạng CSV:
$ ./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
...
Lệnh ls liệt kê nội dung của một thư mục. Sử dụng ls 20*.csv
để liệt kê tất cả các tệp của bạn có tên bắt đầu bằng 20 và kết thúc bằng .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. Trích xuất nhiệt độ trung bình
Trích xuất dữ liệu TAVG (nhiệt độ trung bình) từ CSV cho các vùng của Hoa Kỳ:
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
Tập lệnh này:
$ ./extract_tavg_us.sh
2010.csv -> TAVG_US_2010.csv
...
2019.csv -> TAVG_US_2019.csv
tạo các tệp này:
$ 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
Đây là vài dòng đầu tiên cho 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,
Lệnh head là một tiện ích để hiển thị một số dòng đầu tiên (theo mặc định là 10 dòng) của tệp.
Dữ liệu có nhiều thông tin hơn bạn cần. Giới hạn số lượng cột bằng cách loại bỏ cột 3 (vì tất cả dữ liệu là nhiệt độ trung bình) và cột 5 trở đi. Nói cách khác, giữ các cột 1 (trạm khí hậu), 2 (ngày tháng) và 4 (ghi nhiệt độ).
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
Chạy tập lệnh:
$ ./key_columns.sh
Extracting columns TAVG_US_2010.csv
...
Extracting columns TAVG_US_2019.csv
Vài dòng đầu tiên của TAVG_US_2010.csv
với dữ liệu không cần thiết bị xóa là:
$ 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
Ngày ở dạng chuỗi (YMD). Để đào tạo mô hình của bạn một cách chính xác, các thuật toán của bạn cần nhận ra các trường ngày trong biểu mẫu Y, M, D được phân tách bằng dấu phẩy (Ví dụ:20100101
trở thành 2010,01,01
). Bạn có thể chuyển đổi chúng bằng tiện ích sed.
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
Chạy tập lệnh:
$ ./date_format.sh
Date formatting TAVG_US_2010.csv
...
Date formatting TAVG_US_2019.csv
Vài dòng đầu tiên của TAVG_US_2010.csv
với định dạng ngày được phân tách bằng dấu phẩy là:
$ 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. Tổng hợp dữ liệu nhiệt độ trung bình của các tiểu bang
Dữ liệu thời tiết đến từ các trạm khí hậu đặt tại các thành phố của Hoa Kỳ, nhưng bạn muốn dự báo nhiệt độ của toàn tiểu bang. Để chuyển đổi dữ liệu trạm khí hậu thành dữ liệu trạng thái, trước tiên, hãy lập bản đồ các trạm khí hậu với trạng thái của chúng.
Tải xuống danh sách các trạm khí hậu bằng cách sử dụng wget:
$ wget ftp://ftp.ncdc.noaa.gov/pub/data/ghcn/daily/ghcnd-stations.txt
Trích xuất các đài của Hoa Kỳ với tiện ích grep để tìm danh sách của Hoa Kỳ. Lệnh sau tìm kiếm các dòng bắt đầu bằng văn bản "US
. ">
là chuyển hướng ghi đầu ra vào một tệp — trong trường hợp này là vào tệp có tên us_stations.txt
:
$ grep "^US" ghcnd-stations.txt > us_stations.txt
Tệp này được tạo cho bản in đẹp, vì vậy các dấu phân tách cột không nhất quán:
$ 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
...
Làm cho chúng nhất quán bằng cách sử dụng cat để in tệp, sử dụng tr để ép các lần lặp lại và xuất ra tệp tạm thời, đồng thời đổi tên tệp tạm trở lại như ban đầu — tất cả trong một dòng:
$ cat us_stations.txt | tr -s ' ' > us_stations.txt.tmp; cp us_stations.txt.tmp us_stations.txt;
Các dòng đầu tiên của đầu ra của lệnh:
$ 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
...
Điều này chứa rất nhiều thông tin — tọa độ GPS và những thứ khác — nhưng bạn chỉ cần mã trạm và trạng thái. Sử dụng cắt:
$ cut -d' ' -f1,5 us_stations.txt > us_stations.txt.tmp; mv us_stations.txt.tmp us_stations.txt;
Các dòng đầu tiên của đầu ra của lệnh:
$ head us_stations.txt
US009052008 SD
US10RMHS145 CO
US10adam001 NE
US10adam002 NE
...
Đặt đây là CSV và thay đổi khoảng trắng thành dấu phân cách bằng dấu phẩy bằng cách sử dụng sed:
$ sed -i s/' '/,/g us_stations.txt
Các dòng đầu tiên của đầu ra của lệnh:
$ head us_stations.txt
US009052008,SD
US10RMHS145,CO
US10adam001,NE
US10adam002,NE
...
Mặc dù bạn đã sử dụng một số lệnh cho các tác vụ này, bạn vẫn có thể thực hiện tất cả các bước trong một lần chạy. Hãy tự mình thử.
Bây giờ, hãy thay thế các mã trạm bằng các vị trí trạng thái của chúng bằng cách sử dụng AWK, có hiệu suất cao về mặt chức năng để xử lý dữ liệu lớn.
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
Đây là ý nghĩa của các thông số này:
-F, | Dấu phân tách trường là , |
FNR | Số dòng trong mỗi tệp |
NR | Số dòng trong cả hai tệp cùng nhau |
FNR==NR | Chỉ có trong tệp đầu tiên ${PATTERN_FILE} |
{ x[$1]=$2; next; } | Nếu FNR==NR là TRUE (cho tất cả các dòng trong $PATTERN_FILE duy nhất) |
- x | Biến để lưu trữ station=state bản đồ |
- x[$1]=$2 | Thêm dữ liệu của station=state bản đồ |
- $1 | Cột đầu tiên trong tệp đầu tiên (mã trạm) |
- $2 | Cột thứ hai trong tệp đầu tiên (mã tiểu bang) |
- x | Bản đồ của tất cả các trạm, ví dụ:x[US009052008]=SD , x[US10RMHS145]=CO , ..., x[USW00096409]=AK |
- next | Chuyển đến dòng tiếp theo đối sánh FNR==NR (về cơ bản, điều này tạo ra một bản đồ của tất cả các trạng thái trạm từ ${PATTERN_FILE} |
{ $1=x[$1]; print $0 } | Nếu FNR==NR là FALSE (cho tất cả các dòng in $DATA_FILE duy nhất) |
- $1=x[$1] | Thay thế trường đầu tiên bằng x[$1] ; về cơ bản, thay thế mã trạm bằng mã tiểu bang |
- print $0 | In tất cả các cột (bao gồm cả $1 đã thay thế ) |
OFS=, | Dấu phân tách các trường đầu ra là , |
CSV có mã trạm:
$ 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
Chạy lệnh:
$ ./station_to_state_data.sh
TAVG_US_2010.csv
...
TAVG_US_2019.csv
Các trạm hiện được ánh xạ tới các trạng thái:
$ 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
Mỗi tiểu bang đều có một số chỉ số nhiệt độ cho mỗi ngày, vì vậy bạn cần tính giá trị trung bình của các chỉ số của mỗi tiểu bang trong một ngày. Sử dụng AWK để xử lý văn bản, sắp xếp để đảm bảo kết quả cuối cùng theo thứ tự hợp lý và rm để xóa tệp tạm thời sau khi xử lý.
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
Đây là ý nghĩa của các tham số AWK:
FILE=$DATA_FILE | Tệp CSV được xử lý dưới dạng FILE |
-F, | Dấu phân tách trường là , |
state_day_sum[$1 "," $2 "," $3 "," $4] = $5 | Tổng nhiệt độ ($5 ) cho trạng thái ($1 ) vào năm ($2 ), tháng ($3 ), ngày ($4 ) |
state_day_num[$1 "," $2 "," $3 "," $4] = $5 | Số lần đọc nhiệt độ cho trạng thái ($1 ) vào năm ($2 ), tháng ($3 ), ngày ($4 ) |
END | Cuối cùng, sau khi thu thập tổng và số lần đọc cho tất cả các trạng thái, năm, tháng, ngày, hãy tính giá trị trung bình |
for (state_day_key in state_day_sum) | Đối với mỗi tiểu bang-năm-tháng-ngày |
print state_day_key "," state_day_sum[state_day_key]/state_day_num[state_day_key] | Trạng thái in, năm, tháng, ngày, trung bình |
OFS=, | Dấu phân tách các trường đầu ra là , |
$DATA_FILE | Tệp đầu vào (tất cả các tệp có tên bắt đầu bằng TAVG_US_ và kết thúc bằng .csv , từng cái một) |
> STATE_DAY_${DATA_FILE}.tmp | Lưu kết quả vào tệp tạm thời |
Chạy tập lệnh:
$ ./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
Các tệp này được tạo:
$ 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
Xem dữ liệu một năm cho tất cả các trạng thái (ít hơn là một tiện ích để xem đầu ra một trang tại một thời điểm):
$ 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
Hợp nhất tất cả các tệp dữ liệu thành một:
$ cat STATE_DAY_TAVG_US_20*.csv > TAVG_US_2010-2019.csv
Giờ đây, bạn có một tệp, với tất cả các trạng thái, cho tất cả các năm:
$ 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. Tạo dữ liệu chuỗi thời gian
Một vấn đề như thế này được giải quyết một cách phù hợp với mô hình chuỗi thời gian như bộ nhớ ngắn hạn dài (LSTM), là mạng nơ-ron định kỳ (RNN). Dữ liệu đầu vào này được sắp xếp thành các lát thời gian; coi 20 ngày là một lát.
Đây là phần một lần (như trong 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
Phần thời gian này được biểu thị bằng (các giá trị nhiệt độ trong đó 20 tuần đầu tiên là X và 21 là y):
AK, -181.934,-199.531, ... ,
-157.273,-165.3
Các lát cắt liền kề nhau theo thời gian. Ví dụ:cuối năm 2010 tiếp tục sang năm 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
Kết quả dự đoán:
AK,2011,01,11,-106.851
Phần thời gian này được coi là:
AK, -209.92, ... ,-79.8523,-59.5658, ... ,-100.623,-106.851
và như vậy, cho tất cả các tiểu bang, năm, tháng và ngày. Để biết thêm giải thích, hãy xem hướng dẫn này về dự báo chuỗi thời gian.
Viết tập lệnh để tạo các lát thời gian:
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
Chạy tập lệnh. Nó sử dụng khoảng trắng làm dấu phân cách cột; đặt chúng thành dấu phẩy với sed:
$ ./timeslices.sh > TIMESLICE_TAVG_US_2010-2019.csv; sed -i s/' '/,/g TIME_VARIANT_TAVG_US_2010-2019.csv
Đây là vài dòng đầu tiên và vài dòng cuối cùng của đầu ra .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
Mặc dù điều này có hiệu quả, nhưng nó không hiệu quả lắm. Nó có thể được tối ưu hóa — bạn có thể thử không? Báo cáo trong phần nhận xét bên dưới cách bạn đã làm.
5. Tạo huấn luyện, kiểm tra và xác thực tập dữ liệu
Tách dữ liệu thành train , kiểm tra và xác thực bộ.
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
Điều này tạo ra các tập dữ liệu có thể tuần tự hoặc ngẫu nhiên bằng cách đặt GEN=SEQ
hoặc GEN=RAN
trong script và bạn có thể trộn dữ liệu bằng shuf.
Chạy tập lệnh:
$ ./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
Để tạo các tệp dữ liệu này:
$ 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
Xử lý dữ liệu với shell
Khi bạn cần xử lý một lượng lớn dữ liệu cho dự án học máy tiếp theo của mình, hãy nghĩ đến các lệnh và tập lệnh shell. Nó đã được chứng minh và sẵn sàng sử dụng với các cộng đồng thân thiện để hướng dẫn và giúp đỡ bạn.
Bài viết này giới thiệu một trình bao để xử lý dữ liệu và các tập lệnh thể hiện các cơ hội. Nhiều hơn nữa là có thể. Bạn có muốn đưa nó về phía trước? Hãy cho chúng tôi biết trong phần bình luận bên dưới.