R 展平分隔的复合列
我在R中得到了一个数据帧,其中一个字段是复合的(分隔的)。下面是我得到的一个例子:R 展平分隔的复合列,r,R,我在R中得到了一个数据帧,其中一个字段是复合的(分隔的)。下面是我得到的一个例子: users=c(1,2,3) items=c("23 77 49", "10 18 28", "20 31 84") df = data.frame(users,items) (我不构建它;这只是为了说明。) 我想展平第二列,以便获得(非唯一的)用户ID列表和每行一项。因此,我想以: user item 1 23 1 77 1 49 2 10 2
users=c(1,2,3)
items=c("23 77 49", "10 18 28", "20 31 84")
df = data.frame(users,items)
(我不构建它;这只是为了说明。)
我想展平第二列,以便获得(非唯一的)用户ID列表和每行一项。因此,我想以:
user item
1 23
1 77
1 49
2 10
2 18
2 28
3 20
3 31
3 84
我试过:
data.frame(user = df$users, item = unlist(strsplit(as.character(df$items), " ")))
但我得到“参数意味着不同的行数”。我明白为什么,但找不到解决方案来给我想要的结果。有什么想法吗
还有,当我得到超过2000万行时,最有效的方法是什么?
itemsitems这里是一个dplyr
解决方案
items <- strsplit(df$items, " ")
data.frame(user = rep(df$users, sapply(items, length)), item = unlist(items))
## user item
## 1 1 23
## 2 1 77
## 3 1 49
## 4 2 10
## 5 2 18
## 6 2 28
## 7 3 20
## 8 3 31
## 9 3 84
users=c(1,2,3)
items=c("23 77 49", "10 18 28", "20 31 84")
df = data.frame(users,items,stringsAsFactors=FALSE)
rbind_all(do(df %.% group_by(users),
.f = function(d) data.frame(d[,1,drop=FALSE],
items = unlist(strsplit(d[['items']],' ')),
stringsAsFactors=FALSE)))
如果有一个展开
功能,也就是说,与总结
如果下面的方法行得通
df %.% group_by(users) %.% expand(unlist(strsplit(items,' ')))
下面是一个dplyr
解决方案
users=c(1,2,3)
items=c("23 77 49", "10 18 28", "20 31 84")
df = data.frame(users,items,stringsAsFactors=FALSE)
rbind_all(do(df %.% group_by(users),
.f = function(d) data.frame(d[,1,drop=FALSE],
items = unlist(strsplit(d[['items']],' ')),
stringsAsFactors=FALSE)))
如果有一个展开
功能,也就是说,与总结
如果下面的方法行得通
df %.% group_by(users) %.% expand(unlist(strsplit(items,' ')))
如果您愿意安装我的“SOfun”软件包或加载我的,并且如果每个“item”字符串中有相同数量的项(在您的示例中,有3个),则以下可能是一个选项:
library(reshape2)
library(data.table)
melt(concat.split.DT(indf, "items", " "), id.vars="users")
这里有一个例子
示例数据:3行、3000行和3000000行
我添加了一个“id”列,以便您可以比较两个选项的输出
## your sample data.frame
df <- data.frame(users=c(1,2,3),
items=c("23 77 49", "10 18 28", "20 31 84"))
## extended to 3000 rows
df1k <- df[rep(rownames(df), 1000), ]
df1k$id <- sequence(nrow(df1k))
## extended to 3 million rows
df1m <- df1M <- df[rep(rownames(df), 1000000), ]
df1m$id <- sequence(nrow(df1m))
下面是一些测试Jake回答速度的函数,还有这个。稍后我也会尝试使用“dplyr”进行更新
在300万行上测试(仅一次)
这里的时间单位是秒
system.time(fun1(df1m))
# user system elapsed
# 7.71 0.94 8.69
system.time(fun2(df1m))
# user system elapsed
# 177.80 0.50 178.97
更新
@杰克在评论中提出了一个很好的观点,即添加一个“id”在时间安排上有很大的不同。我添加它只是为了方便比较两种数据.table
方法的输出,以查看结果是否相同
在fun1
和fun2
中删除“id”列并删除对“id”的引用,我们可以得到以下信息:
microbenchmark(fun1a(df1M), fun2a(df1M), fun3(df1M), times = 5)
# Unit: seconds
# expr min lq median uq max neval
# fun1a(df1M) 2.307313 2.420845 2.630284 2.822011 3.074464 5
# fun2a(df1M) 12.480502 12.491783 12.761392 13.069169 13.733686 5
# fun3(df1M) 13.976329 14.281856 14.471252 15.041450 15.089593 5
上述基准还包括fun3
,这是@mnel的“dplyr”方法
fun3 <- function(indf) {
rbind_all(do(indf %.% group_by(users),
.f = function(d) data.frame(
d[,1,drop=FALSE],
items = unlist(strsplit(as.character(d[['items']]),' ')),
stringsAsFactors=FALSE)))
}
fun3如果您愿意安装我的“SOfun”软件包或加载我的,并且如果每个“item”字符串中有相同数量的项(在您的示例中,有3个),则以下可能是一个选项:
library(reshape2)
library(data.table)
melt(concat.split.DT(indf, "items", " "), id.vars="users")
这里有一个例子
示例数据:3行、3000行和3000000行
我添加了一个“id”列,以便您可以比较两个选项的输出
## your sample data.frame
df <- data.frame(users=c(1,2,3),
items=c("23 77 49", "10 18 28", "20 31 84"))
## extended to 3000 rows
df1k <- df[rep(rownames(df), 1000), ]
df1k$id <- sequence(nrow(df1k))
## extended to 3 million rows
df1m <- df1M <- df[rep(rownames(df), 1000000), ]
df1m$id <- sequence(nrow(df1m))
下面是一些测试Jake回答速度的函数,还有这个。稍后我也会尝试使用“dplyr”进行更新
在300万行上测试(仅一次)
这里的时间单位是秒
system.time(fun1(df1m))
# user system elapsed
# 7.71 0.94 8.69
system.time(fun2(df1m))
# user system elapsed
# 177.80 0.50 178.97
更新
@杰克在评论中提出了一个很好的观点,即添加一个“id”在时间安排上有很大的不同。我添加它只是为了方便比较两种数据.table
方法的输出,以查看结果是否相同
在fun1
和fun2
中删除“id”列并删除对“id”的引用,我们可以得到以下信息:
microbenchmark(fun1a(df1M), fun2a(df1M), fun3(df1M), times = 5)
# Unit: seconds
# expr min lq median uq max neval
# fun1a(df1M) 2.307313 2.420845 2.630284 2.822011 3.074464 5
# fun2a(df1M) 12.480502 12.491783 12.761392 13.069169 13.733686 5
# fun3(df1M) 13.976329 14.281856 14.471252 15.041450 15.089593 5
上述基准还包括fun3
,这是@mnel的“dplyr”方法
fun3 <- function(indf) {
rbind_all(do(indf %.% group_by(users),
.f = function(d) data.frame(
d[,1,drop=FALSE],
items = unlist(strsplit(as.character(d[['items']]),' ')),
stringsAsFactors=FALSE)))
}
fun3每个“项目”行中的项目数量是否始终相同?@AnandaMahto No。每行可以有不同数量的分隔项目。每个“项目”中的项目数量是否始终相同行?@AnandaMahto-No。每行可以有不同数量的分隔项。添加id
列似乎可以改变一些事情lot@JakeBurkhead你说得对。我添加了它,这样可以更容易地比较和验证输出是否包含相同的数据。我已经更新了一个基准,显示了删除“id”后的情况。感谢更新基准。这些都是我在没有id
的情况下运行它时看到的情况。添加id
列似乎改变了很多事情lot@JakeBurkhead你说得对。我添加了它,这样可以更容易地比较和验证输出是否包含相同的数据。我已经更新了一个基准,显示了删除“id”后的情况。感谢更新基准。这些都是我在没有id
的情况下运行它时看到的情况。这是一些不错的性能。这似乎反转了输出中的“用户”列。你知道为什么吗?@AnandaMahto-它确实对订单做了一些奇怪的事情。不完全相反。我可能会报告这一点。@AnandaMahto--这似乎是由于用户类的原因。看,这是一场精彩的演出。这似乎反转了输出中的“用户”列。你知道为什么吗?@AnandaMahto-它确实对订单做了一些奇怪的事情。不完全相反。我可能会报告这一点。@AnandaMahto--这似乎是由于用户类的原因。作为一种非常简单易读的方法,我喜欢数据。table
选项a lot+1作为一种非常简单易读的方法,我喜欢数据。table
选项a lot+1