(我很抱歉我的例子过于简单,我将尝试解决这个问题,并以更方便的格式格式化我更相关的示例,以便直接复制到R中。特别是,有多个值列,以及前面一些不需要解析的其他信息的列。
我对R和data.table都不熟悉,所以我希望能就我发现的一个问题提供意见。我正在处理一个数据表,其中一列是冒号分隔的格式字符串,作为其他冒号分隔列中值的图例。为了解析它,我必须首先将其拆分为它的组件,然后搜索我需要稍后索引值字符串的组件的索引。这是我可能处理的那种情况的一个简化示例
DT <- data.table(number=c(1:5),
format=c("name:age","age:name","age:name:height","height:age:name","weight:name:age"),
person1=c("john:30","40:bill","20:steve:100","300:70:george","140:fred:20"),
person2=c("jane:31","42:ivan","21:agnes:120","320:72:vivian","143:rose:22"))
当评估时,我们得到
> DT
number format person1 person2
1: 1 name:age john:30 jane:31
2: 2 age:name 40:bill 42:ivan
3: 3 age:name:height 20:steve:100 21:agnes:120
4: 4 height:age:name 300:70:george 320:72:vivian
5: 5 weight:name:age 140:fred:20 143:rose:22
假设对于每个人,我只需要知道他们的姓名和年龄,而不需要他们的身高或体重;在这个例子中,以及在我的实际数据中,每个格式字符串都有姓名和年龄的字段,但可能在不同的位置(我实际寻找的字段通常固定在某些列中,但我不愿意硬编码任何索引,因为我不完全熟悉我正在使用的数据文件的生成)。我会首先拆分格式字符串,然后执行匹配()搜索我想要的字段的名称。
DT[, format.split := strsplit(format, ":")]
在这一点上,我用来执行匹配的唯一方法是vapply:
DT[, index.name := vapply(format.split, function (x) match('name', x), 0L)]
DT[, index.age := vapply(format.split, function (x) match('age', x), 0L)]
因为我不知道有什么其他方法可以让R知道它应该单独查看列中的行,而不是作为向量聚在一起,并对向量值格式执行匹配。拆分每行的列,而不是尝试匹配整列行。即使如此,一旦我找到了每行的索引,我必须执行另一个strsplit,然后执行一个mapply,从每个人的值字符串中解析姓名值和年龄值:
DT[, person1.split := strsplit(person1, ':')]
DT[, person1.name := mapply(function (x,y) x[y], person1.split, index.name]
DT[, person1.age := mapply(function (x,y) x[y], person1.split, index.age]
DT[, person2.split := strsplit(person2, ':')]
DT[, person2.name := mapply(function (x,y) x[y], person2.split, index.name]
DT[, person2.age := mapply(function (x,y) x[y], person2.split, index.age]
(当然,我也会对年龄做同样的事情)
我正在处理相当大的数据集,因此我希望我的代码尽可能高效。有人对我可以加速或以其他方式优化我的代码的方法有建议吗?
(注意:我真的在寻找正确的方法,而不是使用正确的*Application或*ply或Map函数。如果*(ap)ply或Map真的是正确的方法,我会很感激知道哪种方法最有效或最适合我的情况,但如果有更好的方法来测试行内重复,我更喜欢关于它的建议而不是功能建议。不过,欢迎提出建议)。
事实证明,我的html" target="_blank">示例比它需要的要普遍得多。我只需要两个字段,它们总是格式字符串中的前两个字段,没有变化。第一个字段只是一个文字字符串。然而,第二个字段至少由2个数字组成,用逗号分隔(最终,我会过滤掉第二个字段中超过2个数字的任何行,因此只有在解析后进行过滤时,更多的可能性才相关)。对于(3)个值字符串中的每一个,我只需要创建三列:第一个字段的字符列和两个数字列,第二个字段中逗号分隔对的每个成员一个。任何其他字段都是无关紧要的。我目前的方法可能效率很低,是使用sub()在所需的字段和子字段上使用反向引用进行模式匹配。
> DT <- data.table(id=1:5,
format=c(rep("A:B:C:D:E", 5)),
person1=paste(paste0("foo",LETTERS[1:5]), paste(1:5, 10:6, sep=','), "blah", "bleh", "bluh", sep=':'),
person2=paste(paste0("bar",LETTERS[1:5]), paste(16:20, 5:1, sep=','), "blah", "bleh", "bluh", sep=':'),
person3=paste(paste0("baz",LETTERS[1:5]), paste(0:4, 12:8, sep=','), "blah", "bleh", "bluh", sep=':'))
> DT
id format person1 person2 person3
1: 1 A:B:C:D:E fooA:1,10:blah:bleh:bluh barA:16,5:blah:bleh:bluh bazA:0,12:blah:bleh:bluh
2: 2 A:B:C:D:E fooB:2,9:blah:bleh:bluh barB:17,4:blah:bleh:bluh bazB:1,11:blah:bleh:bluh
3: 3 A:B:C:D:E fooC:3,8:blah:bleh:bluh barC:18,3:blah:bleh:bluh bazC:2,10:blah:bleh:bluh
4: 4 A:B:C:D:E fooD:4,7:blah:bleh:bluh barD:19,2:blah:bleh:bluh bazD:3,9:blah:bleh:bluh
5: 5 A:B:C:D:E fooE:5,6:blah:bleh:bluh barE:20,1:blah:bleh:bluh bazE:4,8:blah:bleh:bluh
然后我的代码会这样做:
DT[, `:=`(person1.A=sub("^([^:]*):.*$","\\1", person1),
person2.A=sub("^([^:]*):.*$","\\1", person2),
person3.A=sub("^([^:]*):.*$","\\1", person3),
person1.B.first=sub("^[^:]*:([^:,]*),.*$","\\1", person1),
person1.B.second=sub("^[^:]*:[^:,]*,([^:,]*)(,[^:,]*)*:.*$","\\1", person1),
person2.B.first=sub("^[^:]*:([^:,]*),.*$","\\1", person2),
person2.B.second=sub("^[^:]*:[^:,]*,([^:,]*)(,[^:,]*)*:.*$","\\1", person2),
person3.B.first=sub("^[^:]*:([^:,]*),.*$","\\1", person3),
person3.B.second=sub("^[^:]*:[^:,]*,([^:,]*)(,[^:,]*)*:.*$","\\1", person3))]
用于拆分,筛选依据
DT <- DT[grepl("^[^:]*:[^:,]*,[^:,]*:.*$", person1) &
grepl("^[^:]*:[^:,]*,[^:,]*:.*$", person2) &
grepl("^[^:]*:[^:,]*,[^:,]*:.*$", person3) ]
我知道这种方法可能非常低效,但这是我对重复应用strsplit的旧方法提出的第一个改进。考虑到新的条件,有没有比熔化,csplit,铸造更好的做事方式?
因为我只需要前两个字段,所以最后我修剪了所有的值字符串,删除了那些超过两个逗号的字符串(即超过3个第二字段的数字),将逗号改为冒号,将每一行的格式字符串替换为(现在是3个)字段的名称,并按照@AnandaMahto的建议执行dcast(csplit(melt))。看起来效果不错。
我认为你可能会更好地使用一个高大整齐的格式:
colonMelt <- function(DT) {
formats <- strsplit(DT$format, ":")
rows <- rep(row.names(DT), sapply(formats, length))
data.frame(row = rows,
key = unlist(formats),
value = unlist(strsplit(DT$values, ":"))
)
}
newDT <- colonMelt(DT)
结果是一种更容易进行搜索和过滤的格式,而不用一直拆分字符串:
row key value
1 1 name john
2 1 age 30
3 2 name rene
4 2 age 33
5 2 height 183
6 3 age 100
7 3 height 10
8 3 name speck
@bskaggs有一个正确的想法,那就是把你的数据放入一个长表单,甚至是一个结构化的宽表单,可能会更有意义。
我将向您展示两个选项,但首先,以其他人可以实际使用的方式共享您的数据总是更好:
DT <- data.table(
format = c("name:age", "name:age:height", "age:height:name",
"height:weight:name:age", "name:age:weight:height",
"name:age:height:weight"),
values = c("john:30", "rene:33:183", "100:10:speck",
"100:400:sumo:11", "james:43:120:120",
"plink:2:300:400"))
我还建议你使用我的< code>cSplit函数。
以下是如何轻松地将数据集转换为长格式:
cSplit(DT, c("format", "values"), ":", "long")
# format values
# 1: name john
# 2: age 30
# 3: name rene
# 4: age 33
# 5: height 183
# 6: age 100
# 7: height 10
# 8: name speck
# 9: height 100
# 10: weight 400
# 11: name sumo
# 12: age 11
# 13: name james
# 14: age 43
# 15: weight 120
# 16: height 120
# 17: name plink
# 18: age 2
# 19: height 300
# 20: weight 400
一旦数据处于“长”形式,就可以使用<code>dcast.data轻松地将其转换为“宽”形式。表,如下所示。(我还使用<code>setcolorder
X <- dcast.data.table(
cSplit(cbind(id = 1:nrow(DT), DT),
c("format", "values"), ":", "long"),
id ~ format, value.var = "values")
setcolorder(X, c("id", "name", "age", "height", "weight"))
X
# id name age height weight
# 1: 1 john 30 NA NA
# 2: 2 rene 33 183 NA
# 3: 3 speck 100 10 NA
# 4: 4 sumo 11 100 400
# 5: 5 james 43 120 120
# 6: 6 plink 2 300 400
从速度的角度看,情况如何?
首先,一个非常适中的数据集:
DT <- rbindlist(replicate(2000, DT, FALSE))
dim(DT)
# [1] 12000 2
## @bskaggs's suggestion
system.time(colonMelt(DT))
# user system elapsed
# 0.27 0.00 0.27
## cSplit. It would be even faster if you already had
## an id column and didn't need to cbind one in
system.time(cSplit(cbind(id = 1:nrow(DT), DT),
c("format", "values"), ":", "long"))
# user system elapsed
# 0.02 0.00 0.01
## cSplit + dcast.data.table
system.time(dcast.data.table(
cSplit(cbind(id = 1:nrow(DT), DT),
c("format", "values"), ":", "long"),
id ~ format, value.var = "values"))
# user system elapsed
# 0.08 0.00 0.08
对于您更新的问题,您可以先融化
data.table,然后类似地进行:
library(reshape2)
## Melting, but no reshaping -- a nice long format
cSplit(melt(DT, id.vars = c("number", "format")),
c("format", "value"), ":", "long")
## Try other combinations for the LHS and RHS of the
## formula. This seems to be what you might be after
dcast.data.table(
cSplit(melt(DT, id.vars = c("number", "format")),
c("format", "value"), ":", "long"),
number ~ variable + format, value.var = "value")
我知道这应该很简单,但是我想从熊猫数据框中取一列,并且只对满足某些条件(比如小于1)的条目乘以标量(比如2)。 例如,在这个数据框中, 如果我有兴趣在列上执行此操作,结果应该是 我有以下绝对任务: 但是我不知道如何使用中的实际值。 提前谢谢!
我有一个猫鼬模式 我最初设置了名称和电话字段的集合。我需要将集合更新为消息数组中的新消息和新地址到地址对象中。该函数还必须处理任何单个操作,即在某些情况下我只更新到消息数组或更新到名称和地址。所以我如何在单个函数中执行所有操作。
我正在尝试根据枚举值检索一个值。基本上,假设我有以下枚举: 通过执行auth.key.get()将返回“MyKey”,而auth.mail.get()将返回“MyMail”。我搜索了一下,但没有找到答案,我之前没有尝试过任何事情,因为我完全不知道如何开始。谢谢,祝你有个愉快的一天
我想替换一行数据的每个值。帧,对于大小相等的逻辑矩阵,其值为TRUE,由向量的对应行的值确定。以下是一个例子: 所以结果应该是这样的: 有没有不使用循环的方法来实现这一点?谢谢
Redisson 支持对每个操作自动重试的策略并且在每次尝试期会尝试发送命令。 重试策略由设置项 retryAttempts (默认为 3) 和 retryInterval (默认为 1000 ms) 来控制。 每次尝试会在 retryInterval 时间间隔后执行。 Redisson 实例和 Redisson 对象都是完全线程安全的。 带有同步/异步方法的 Redisson 对象可通过 Red
我试图弄清楚如何在使用actor系统时最好地处理数据库操作。事实上,数据库操作正在阻塞,而我们试图在Akka中不阻塞。 我在主文档中提到了一种处理方法,那就是在路由器后面创建一个参与者池,可能是在一个单独的executionContext上,它将处理数据库访问。