r-基于列名模式重塑大数据



我有一个(实际上是很大的(带有街道街区的数据集;它具有块的开始(在下面的变量中为"from"(和结束("to"(的门牌号码,用于右侧和左侧。这里有一个例子:

library(data.table)
# raw address file
raw <- data.table(id = letters[1:4],
rfrom = c(1, 101, 201, 301),
rto = c(99, 199, 299, 399),
lfrom = c(2, 102, 202, 302),
lto = c(100, 200, 300, 400),
street = c('birch st',
'main st',
'birch st',
'elm rd'),
rlat = c(1, 11, 21, 31),
llat = c(2, 12, 22, 32))
# for illustration only, hence the nonsensical coordinates

我想重塑这个长度,这样我就可以对每个块的左侧和右侧进行一次观察。我打算使用data.table中的melt,它确实给出了正确的结果:

long <- melt(raw,
id.vars = c('id', 'street'),
measure.vars = patterns('from', 'to', 'lat'),
value.name = c('from', 'to', 'lat'))
# this produces the dataset I want:
long
id   street variable from  to lat
1:  a birch st        1    1  99   1
2:  b  main st        1  101 199  11
3:  c birch st        1  201 299  21
4:  d   elm rd        1  301 399  31
5:  a birch st        2    2 100   2
6:  b  main st        2  102 200  12
7:  c birch st        2  202 300  22
8:  d   elm rd        2  302 400  32

然而,我意识到它的融化是基于列的位置,而不是列名的内容(即,我希望它看到名称中的"r"或"l"前缀(,因为例如,如果你列出一个";左侧";变量在等价的右变量之前,同时保持所有其他变量在左之前,它返回错误的结果:

# now switch the order of the latitude variables:
raw <- data.table(id = letters[1:4],
rfrom = c(1, 101, 201, 301),
rto = c(99, 199, 299, 399),
lfrom = c(2, 102, 202, 302),
lto = c(100, 200, 300, 400),
street = c('birch st',
'main st',
'birch st',
'elm rd'),
llat = c(2, 12, 22, 32),
rlat = c(1, 11, 21, 31))
# melt then gives us incorrect results:
long <- melt(raw,
id.vars = c('id', 'street'),
measure.vars = patterns('from', 'to', 'lat'),
value.name = c('from', 'to', 'lat'))
# latitudes are associated with the wrong observation now:
long
id   street variable from  to lat
1:  a birch st        1    1  99   2
2:  b  main st        1  101 199  12
3:  c birch st        1  201 299  22
4:  d   elm rd        1  301 399  32
5:  a birch st        2    2 100   1
6:  b  main st        2  102 200  11
7:  c birch st        2  202 300  21
8:  d   elm rd        2  302 400  31
# in a related, but less important issue, I'd prefer the variable column list l or r not 1 or 2

显然,重新排序列是一种选择,但我更愿意避免它,主要是因为随着程序的变化,其他人在其中进行编辑等,特别是考虑到在融化后检查结果是否正确是多么困难,依赖它让我觉得很难。(在理想的情况下,我会在长数据集中有一个前缀为l/r的变量。(

这似乎是一个已知的问题,但是——我猜我误解了什么——我尝试使用新的measure函数的变通方法没有奏效(我只是得到一个错误,R找不到一个名为measure的函数(。

在这一点上,我认为我最好的选择是从tidyr切换到使用pivot_longer,但我想我会问是否有人能指出我做错了什么,或者让我知道是否有更好/更有效的方法。

我真的很感激任何帮助。

我确信您已经正确地识别了问题:街道的侧面数据("左"或"右"(编码在列名中。这类似于嵌入虹膜数据列名中的花部分("花瓣"one_answers"萼片"(。由于问题的性质,仅靠melt是做不到这项工作的。

根据您的建议,转换此类数据帧并隔离列名中的数据是一种数据透视操作。我发现cdata包中开发的方法非常透明。然而,转换并不是基于模式。。。相反,它使用精心设计且明确的控制表来管理转换。

为了说明,我从您的第二个raw数据表开始。

raw <- data.table(id = letters[1:4],
rfrom = c(1, 101, 201, 301),
rto = c(99, 199, 299, 399),
lfrom = c(2, 102, 202, 302),
lto = c(100, 200, 300, 400),
street = c('birch st',
'main st',
'birch st',
'elm rd'),
llat = c(2, 12, 22, 32),
rlat = c(1, 11, 21, 31))

使用新的键列和值列fromtolat构建控制表,其中键列指示街道的side

control_table <- wrapr::build_frame(
"side" ,  "from",  "to",  "lat" |
"right", "rfrom", "rto", "rlat" |
"left" , "lfrom", "lto", "llat" )
setDT(control_table)

如果不想使用wrar包,可以将控制表构建为传统的数据表。

side <- c("right", "left")
from <- c("rfrom", "lfrom")
to   <- c("rto"  , "lto")
lat  <- c("rlat" , "llat")
control_table <- data.table(side, from, to, lat)

在任何一种情况下,控制表都具有相同的结构。

control_table[]
#>     side  from  to  lat
#> 1: right rfrom rto rlat
#> 2:  left lfrom lto llat

第二步是使用cdata包中的rowrecs_to_blocks()raw进行操作,其中idstreet列被标识为值,以便根据需要重复多次,以完成从行记录(宽(形式到块记录(长(形式的转换。

DT <- cdata::rowrecs_to_blocks(
wideTable     = raw, 
controlTable  = control_table,
columnsToCopy = c("id", "street")
)
setDT(DT)

如果我正确理解你的问题,那么我认为无论你从哪一列开始,这都会产生你想要的表格。注意,街道的侧面数据现在是明确的";坐标";这有助于识别记录。

DT[]
#>    id   street  side from  to lat
#> 1:  a birch st right    1  99   1
#> 2:  a birch st  left    2 100   2
#> 3:  b  main st right  101 199  11
#> 4:  b  main st  left  102 200  12
#> 5:  c birch st right  201 299  21
#> 6:  c birch st  left  202 300  22
#> 7:  d   elm rd right  301 399  31
#> 8:  d   elm rd  left  302 400  32

当然,其他软件包也可以产生类似的结果。我碰巧喜欢cdata转换的一致性。

最新更新