我有一个(实际上是很大的(带有街道街区的数据集;它具有块的开始(在下面的变量中为"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))
使用新的键列和值列from
、to
和lat
构建控制表,其中键列指示街道的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
进行操作,其中id
和street
列被标识为值,以便根据需要重复多次,以完成从行记录(宽(形式到块记录(长(形式的转换。
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转换的一致性。