編者薦語:
需要處理大量EM50數(shù)據(jù)?請看這里!
以下文章來源于生態(tài)學數(shù)據(jù)分析之R和Python ,作者祝介東
主要改進有以下幾點:
盡可能的最大化
data.table
來處理數(shù)據(jù),大家都知道它最大的優(yōu)勢是純 C 寫的,速度快。復雜的轉(zhuǎn)換盡可能使用
dtplyr
,減少操作難度,又兼顧了時間上的考慮。不知什么原因,
dtplyr
在我這里對data.table
的支持不是很足,我沒找到原因的代碼報錯,所以最后一步又使用了部分data.table
的代碼。
下面內(nèi)容,關鍵步驟都有注釋,供大家參考。
先加載需要多次的包:
1library(data.table)
2library(dtplyr)
3library(dplyr, warn.conflicts = FALSE)
4library(stringr)
5library(tidyr)
6library(lubridate)
然后是最重要的部分:
1# 將序列號寫到一個csv 文件內(nèi)讀取
2sn <- fread(file = "./data/EM50_SN.csv")
3
4#部分數(shù)采的通道沒有全部使用,為方便后續(xù)數(shù)據(jù)的處理
5#暫時將深度1000分配各這些通道,方便數(shù)據(jù)處理,
6#因為盡管無傳感器,數(shù)采仍然輸出了無效的數(shù)值。
7#并非一定是 1000,只要沒有該深度的數(shù)據(jù)即可,比如8888
8
9depth_47373 <- c(10, 80, 1000, 140, 150)
10depth_26387 <- c(155, 165, 10, 80, 130)
11
12# 將表頭改一下名字,不用port12345,方便后面處理
13name_47373 <-
14 paste0(c("moist_", "temp_"), rep(depth_47373, each = 2))
15name_26387 <-
16 paste0(c("moist_", "temp_"), rep(depth_26387, each = 2))
17
18# directory and pattern for list.files ------------------------------------
19data_dir <- ("./csvdata/")
20file_pattern <- paste0(sn[, EM50], "*")
21file_pattern <- str_split(file_pattern, pattern = "EM\\*")
22file_dir <- paste0(rep(data_dir, nrow(sn)))
23file_dir <- str_split(file_dir, "\\*\\/$")
24
25# fread 縮短讀數(shù)的時間 ------------------------------------
26# 將所有文檔名和路徑都讀入list
27all_files <-
28 purrr::map2(file_dir, file_pattern, list.files, full.names = TRUE)
29
30# 讀取第一個list,按序列號順序排列
31list_files <-
32 lapply(all_files[[1]],
33 fread,
34 skip = 3,
35 col.names = c("time", name_26387))
36# 按行將list轉(zhuǎn)換為 data.table
37dt_26387 <- rbindlist(list_files)
38
39# 將日期轉(zhuǎn)化為日期格式
40dt_26387[, time := as.POSIXct(time)]
41
42
43# 將數(shù)據(jù)按濕度和溫度整理成列 -----------------------------------------------------------
44dt_26387[, time := as.POSIXct(time)]
45dt_26387 <- melt(
46 dt_26387,
47 measure.vars = name_26387,
48 variable.name = "depth",
49 value.name = "val"
50)
51# 將高度與前面表示的溫度和濕度拆分開
52dt_26387[, c("measure_item", "depth_val") :=
53 tstrsplit(depth, "_", fixed = TRUE)]
54
55# 按 moist 和 temp 將數(shù)據(jù)分開為 list
56dt_26387_split <-
57 split(dt_26387, f = as.factor(dt_26387$measure_item))
58# 再把 list 拼起來,按列
59dt_26387_split <- bind_cols(dt_26387_split)
60
61# 把數(shù)據(jù)名字改正常了,好記,選擇需要的列,其他扔掉
62dt_26387_merge <-
63 dt_26387_split[, `:=`(moisture = val , temprature = val1)]
64dt_26387_merge <-
65 dt_26387_merge[, .(time, moisture, temprature), keyby = depth_val]
66
67# 轉(zhuǎn)換為 lazy_dt,開始 dtplyr
68lazy_26387 <- lazy_dt(dt_26387_merge)
69lazy_26387 <- lazy_26387 %>%
70 rename(depth = depth_val) %>%
71 # 按照15 min 的間隔劃分數(shù)據(jù),并整理
72 # 同時不要忘記分按剖面來處理
73 mutate(sep_15 = floor_date(time, "15 mins")) %>%
74 group_by(depth, sep_15) %>%
75 summarise(
76 moisture = mean(moisture, na.rm = TRUE),
77 temp = mean(temprature, na.rm = TRUE)
78 ) %>%
79 as.data.table()
80
81# 不能使用 separate 繼續(xù)轉(zhuǎn)換 sep_15,不知原因
82# separate error:no applicable method for 'separate_' applied
83# to an object of class "c('dtplyr_step_group', 'dtplyr_step')"
84# 使用 data.table 繼續(xù)
85# 把時間日期拆開了
86lazy_26387[, c("date", "time") :=
87 tstrsplit(sep_15, " ", fixed = TRUE)]
88lazy_26387[, c("year", "month", "day") :=
89 tstrsplit(date, "-", fixed = TRUE)]
90lazy_26387[, c("hour", "minuts", "sec") :=
91 tstrsplit(time, ":", fixed = TRUE)]
92
93# 扔掉不需要的數(shù)據(jù)
94lazy_26387[, `:=`(
95 sep_15 = NULL,
96 sec = NULL,
97 date = NULL,
98 time = NULL
99)]
100
101# 整理另一個序列號 -----------------------------------------------------------
102# 只需要將前面的代碼改換序列號即可
103
104list_files <-
105 lapply(all_files[[2]],
106 fread,
107 skip = 3,
108 col.names = c("time", name_47373))
109# 按行將list轉(zhuǎn)換為 data.table
110dt_47373 <- rbindlist(list_files)
111
112# 將日期轉(zhuǎn)化為日期格式
113dt_47373[, time := as.POSIXct(time)]
114
115
116# 將數(shù)據(jù)按濕度和溫度整理成列 -----------------------------------------------------------
117dt_47373[, time := as.POSIXct(time)]
118dt_47373 <- melt(
119 dt_47373,
120 measure.vars = name_47373,
121 variable.name = "depth",
122 value.name = "val"
123)
124# 將高度與前面表示的溫度和濕度拆分開
125dt_47373[, c("measure_item", "depth_val") :=
126 tstrsplit(depth, "_", fixed = TRUE)]
127
128# 按 moist 和 temp 將數(shù)據(jù)分開為 list
129dt_47373_split <-
130 split(dt_47373, f = as.factor(dt_47373$measure_item))
131# 再把 list 拼起來,按列
132dt_47373_split <- bind_cols(dt_47373_split)
133
134# 把數(shù)據(jù)名字改正常了,好記,選擇需要的列,其他扔掉
135dt_47373_merge <-
136 dt_47373_split[, `:=`(moisture = val , temprature = val1)]
137dt_47373_merge <-
138 dt_47373_merge[, .(time, moisture, temprature), keyby = depth_val]
139
140# 轉(zhuǎn)換為 lazy_dt,開始 dtplyr
141lazy_47373 <- lazy_dt(dt_47373_merge)
142lazy_47373 <- lazy_47373 %>%
143 rename(depth = depth_val) %>%
144 # 按照15 min 的間隔劃分數(shù)據(jù),并整理
145 # 同時不要忘記分按剖面來處理
146 mutate(sep_15 = floor_date(time, "15 mins")) %>%
147 group_by(depth, sep_15) %>%
148 summarise(
149 moisture = mean(moisture, na.rm = TRUE),
150 temp = mean(temprature, na.rm = TRUE)
151 ) %>%
152 as.data.table()
153
154# 不能使用 separate 繼續(xù)轉(zhuǎn)換 sep_15,不知原因
155# separate error:no applicable method for 'separate_' applied
156# to an object of class "c('dtplyr_step_group', 'dtplyr_step')"
157# 使用 data.table 繼續(xù)
158# 把時間日期拆開了
159lazy_47373[, c("date", "time") :=
160 tstrsplit(sep_15, " ", fixed = TRUE)]
161lazy_47373[, c("year", "month", "day") :=
162 tstrsplit(date, "-", fixed = TRUE)]
163lazy_47373[, c("hour", "minuts", "sec") :=
164 tstrsplit(time, ":", fixed = TRUE)]
165
166# 扔掉不需要的數(shù)據(jù)
167lazy_47373[, `:=`(
168 sep_15 = NULL,
169 sec = NULL,
170 date = NULL,
171 time = NULL
172)]
結(jié)果如下:
1#最終處理好的數(shù)據(jù),已經(jīng)按 15 min 來進行整理了:
2knitr::kable(head(lazy_26387))
3knitr::kable(head(lazy_47373))
最終將數(shù)據(jù)導出:
1#最終導出 csv。
2fwrite(lazy_47373, "./final-data/ave26387.csv")
3fwrite(lazy_47373, "./final-data/ave47373.csv")