如何将成对的列移动到行中并同时创建一个 ID?
How can I move pairs of columns into rows and create an ID at the same time?
我有一堆原始数据是从一个优化选项不多的软件中获得的。
当我将它转换为 csv
并读入 R 时,我得到这个:
如您所见,我有 2 种类型的变量,Force
和 Time
,用于 15 个不同的数据包。我想将 Force 和 Time 的所有数据分组为仅 2 列,并使用每个数据集的 ID 创建第三列,如下所示:
ID | Force| Time
------------------------------------
SR_1.5x1.5x1.5_90s 001 | 52.2 | 0.00
SR_1.5x1.5x1.5_90s 001 | 55.3 | 0.04
... | ... | ...
SR_1.5x1.5x1.5_90s 002 | 64.8 | 0.00
SR_1.5x1.5x1.5_90s 002 | 69.6 | 0.04
我尝试使用 tidyr 函数 gather()
但结果并不令人满意。
这是我在这里提出的第一个问题,如果有任何信息遗漏,我深表歉意。
您想首先 gather
所有列,然后 spread
交替 Force
和 Time
行。
首先,我们将您的一小段数据重新创建为:
rtabla1 <- structure(list(SR_1.5x1.5x1.5_90s.001.Force = c(52.2, 55.3, 62.6, 66.5, 70.8, 75.9, 77.6, 78.7, 80.2, 83.8), SR_1.5x1.5x1.5_90s.001.Time = c(0, 0.004, 0.008, 0.012, 0.016, 0.02, 0.024, 0.028, 0.032, 0.036),
SR_1.5x1.5x1.5_90s.002.Force = c(64.8, 69.6, 76, 80.2, 85.1,
90.5, 94.1, 95.6, 99.7, 103.4), SR_1.5x1.5x1.5_90s.002.Time = c(0,
0.004, 0.008, 0.012, 0.016, 0.02, 0.024, 0.028, 0.032, 0.036
)), .Names = c("SR_1.5x1.5x1.5_90s.001.Force", "SR_1.5x1.5x1.5_90s.001.Time", "SR_1.5x1.5x1.5_90s.002.Force", "SR_1.5x1.5x1.5_90s.002.Time"), row.names = c(NA, -10L), class = "data.frame")
## SR_1.5x1.5x1.5_90s.001.Force SR_1.5x1.5x1.5_90s.001.Time SR_1.5x1.5x1.5_90s.002.Force SR_1.5x1.5x1.5_90s.002.Time
##1 52.2 0.000 64.8 0.000
##2 55.3 0.004 69.6 0.004
##3 62.6 0.008 76.0 0.008
##4 66.5 0.012 80.2 0.012
##5 70.8 0.016 85.1 0.016
##6 75.9 0.020 90.5 0.020
##7 77.6 0.024 94.1 0.024
##8 78.7 0.028 95.6 0.028
##9 80.2 0.032 99.7 0.032
##10 83.8 0.036 103.4 0.036
使用 tidyr
和 dplyr
:
library(dplyr)
library(tidyr)
result <- rtabla1 %>% mutate(Row=seq_len(n())) %>% ##1.
gather("ID","Vals",-Row) %>% ##2.
mutate(FT=ifelse(grepl(".Force$",ID), "Force", "Time"), ##3.
ID=sub("(.Force$)|(.Time$)","",ID)) %>%
spread(FT,Vals) %>% ##4.
select(-Row) %>% ##5.
arrange(ID) ##6.
备注:
- 首先添加一个仅包含行号的标识符列。
gather
除 Row
之外的所有列,导致 ID
列包含收集的列名称。
mutate
此 ID
列使用字符串操作形成列 FT
。创建此 FT
列是为了识别收集到的行中哪些是 Force
,哪些是 Time
。后续spread
中会用到。并创建其值以匹配结果的列名(即 "Force"
或 "Time"
)。在这里,使用 grepl
检查 ID
是否以 ".Force"
结尾。如果是,则将 FT
列设置为 "Force"
;否则,将 FT
列设置为 "Time"
。然后,更新 ID
列以从其末尾删除 ".Force"
或 ".Time"
。
- 现在,
spread
使用 FT
作为键和收集的值作为值。
- 从结果中删除
Row
列。
- 排序方式
ID
使用一小段数据的result
符合预期:
print(result)
## ID Force Time
##1 SR_1.5x1.5x1.5_90s.001 52.2 0.000
##2 SR_1.5x1.5x1.5_90s.001 55.3 0.004
##3 SR_1.5x1.5x1.5_90s.001 62.6 0.008
##4 SR_1.5x1.5x1.5_90s.001 66.5 0.012
##5 SR_1.5x1.5x1.5_90s.001 70.8 0.016
##6 SR_1.5x1.5x1.5_90s.001 75.9 0.020
##7 SR_1.5x1.5x1.5_90s.001 77.6 0.024
##8 SR_1.5x1.5x1.5_90s.001 78.7 0.028
##9 SR_1.5x1.5x1.5_90s.001 80.2 0.032
##10 SR_1.5x1.5x1.5_90s.001 83.8 0.036
##11 SR_1.5x1.5x1.5_90s.002 64.8 0.000
##12 SR_1.5x1.5x1.5_90s.002 69.6 0.004
##13 SR_1.5x1.5x1.5_90s.002 76.0 0.008
##14 SR_1.5x1.5x1.5_90s.002 80.2 0.012
##15 SR_1.5x1.5x1.5_90s.002 85.1 0.016
##16 SR_1.5x1.5x1.5_90s.002 90.5 0.020
##17 SR_1.5x1.5x1.5_90s.002 94.1 0.024
##18 SR_1.5x1.5x1.5_90s.002 95.6 0.028
##19 SR_1.5x1.5x1.5_90s.002 99.7 0.032
##20 SR_1.5x1.5x1.5_90s.002 103.4 0.036
我有一堆原始数据是从一个优化选项不多的软件中获得的。
当我将它转换为 csv
并读入 R 时,我得到这个:
如您所见,我有 2 种类型的变量,Force
和 Time
,用于 15 个不同的数据包。我想将 Force 和 Time 的所有数据分组为仅 2 列,并使用每个数据集的 ID 创建第三列,如下所示:
ID | Force| Time
------------------------------------
SR_1.5x1.5x1.5_90s 001 | 52.2 | 0.00
SR_1.5x1.5x1.5_90s 001 | 55.3 | 0.04
... | ... | ...
SR_1.5x1.5x1.5_90s 002 | 64.8 | 0.00
SR_1.5x1.5x1.5_90s 002 | 69.6 | 0.04
我尝试使用 tidyr 函数 gather()
但结果并不令人满意。
这是我在这里提出的第一个问题,如果有任何信息遗漏,我深表歉意。
您想首先 gather
所有列,然后 spread
交替 Force
和 Time
行。
首先,我们将您的一小段数据重新创建为:
rtabla1 <- structure(list(SR_1.5x1.5x1.5_90s.001.Force = c(52.2, 55.3, 62.6, 66.5, 70.8, 75.9, 77.6, 78.7, 80.2, 83.8), SR_1.5x1.5x1.5_90s.001.Time = c(0, 0.004, 0.008, 0.012, 0.016, 0.02, 0.024, 0.028, 0.032, 0.036),
SR_1.5x1.5x1.5_90s.002.Force = c(64.8, 69.6, 76, 80.2, 85.1,
90.5, 94.1, 95.6, 99.7, 103.4), SR_1.5x1.5x1.5_90s.002.Time = c(0,
0.004, 0.008, 0.012, 0.016, 0.02, 0.024, 0.028, 0.032, 0.036
)), .Names = c("SR_1.5x1.5x1.5_90s.001.Force", "SR_1.5x1.5x1.5_90s.001.Time", "SR_1.5x1.5x1.5_90s.002.Force", "SR_1.5x1.5x1.5_90s.002.Time"), row.names = c(NA, -10L), class = "data.frame")
## SR_1.5x1.5x1.5_90s.001.Force SR_1.5x1.5x1.5_90s.001.Time SR_1.5x1.5x1.5_90s.002.Force SR_1.5x1.5x1.5_90s.002.Time
##1 52.2 0.000 64.8 0.000
##2 55.3 0.004 69.6 0.004
##3 62.6 0.008 76.0 0.008
##4 66.5 0.012 80.2 0.012
##5 70.8 0.016 85.1 0.016
##6 75.9 0.020 90.5 0.020
##7 77.6 0.024 94.1 0.024
##8 78.7 0.028 95.6 0.028
##9 80.2 0.032 99.7 0.032
##10 83.8 0.036 103.4 0.036
使用 tidyr
和 dplyr
:
library(dplyr)
library(tidyr)
result <- rtabla1 %>% mutate(Row=seq_len(n())) %>% ##1.
gather("ID","Vals",-Row) %>% ##2.
mutate(FT=ifelse(grepl(".Force$",ID), "Force", "Time"), ##3.
ID=sub("(.Force$)|(.Time$)","",ID)) %>%
spread(FT,Vals) %>% ##4.
select(-Row) %>% ##5.
arrange(ID) ##6.
备注:
- 首先添加一个仅包含行号的标识符列。
gather
除Row
之外的所有列,导致ID
列包含收集的列名称。mutate
此ID
列使用字符串操作形成列FT
。创建此FT
列是为了识别收集到的行中哪些是Force
,哪些是Time
。后续spread
中会用到。并创建其值以匹配结果的列名(即"Force"
或"Time"
)。在这里,使用grepl
检查ID
是否以".Force"
结尾。如果是,则将FT
列设置为"Force"
;否则,将FT
列设置为"Time"
。然后,更新ID
列以从其末尾删除".Force"
或".Time"
。- 现在,
spread
使用FT
作为键和收集的值作为值。 - 从结果中删除
Row
列。 - 排序方式
ID
使用一小段数据的result
符合预期:
print(result)
## ID Force Time
##1 SR_1.5x1.5x1.5_90s.001 52.2 0.000
##2 SR_1.5x1.5x1.5_90s.001 55.3 0.004
##3 SR_1.5x1.5x1.5_90s.001 62.6 0.008
##4 SR_1.5x1.5x1.5_90s.001 66.5 0.012
##5 SR_1.5x1.5x1.5_90s.001 70.8 0.016
##6 SR_1.5x1.5x1.5_90s.001 75.9 0.020
##7 SR_1.5x1.5x1.5_90s.001 77.6 0.024
##8 SR_1.5x1.5x1.5_90s.001 78.7 0.028
##9 SR_1.5x1.5x1.5_90s.001 80.2 0.032
##10 SR_1.5x1.5x1.5_90s.001 83.8 0.036
##11 SR_1.5x1.5x1.5_90s.002 64.8 0.000
##12 SR_1.5x1.5x1.5_90s.002 69.6 0.004
##13 SR_1.5x1.5x1.5_90s.002 76.0 0.008
##14 SR_1.5x1.5x1.5_90s.002 80.2 0.012
##15 SR_1.5x1.5x1.5_90s.002 85.1 0.016
##16 SR_1.5x1.5x1.5_90s.002 90.5 0.020
##17 SR_1.5x1.5x1.5_90s.002 94.1 0.024
##18 SR_1.5x1.5x1.5_90s.002 95.6 0.028
##19 SR_1.5x1.5x1.5_90s.002 99.7 0.032
##20 SR_1.5x1.5x1.5_90s.002 103.4 0.036