R 如何按列顺序返回指定给特定行的值?
我有一个数据框,看起来像这样,可以延伸数百万行:R 如何按列顺序返回指定给特定行的值?,r,data.table,R,Data.table,我有一个数据框,看起来像这样,可以延伸数百万行: id class weight 1: 3930271 77 1.0 2: 3930272 55 0.5 3: 3930272 654 0.5 4: 3930273 66 0.5 5: 3930273 66 0.5 6: 3930274 225 1.0 7
id class weight
1: 3930271 77 1.0
2: 3930272 55 0.5
3: 3930272 654 0.5
4: 3930273 66 0.5
5: 3930273 66 0.5
6: 3930274 225 1.0
7: 3930275 66 0.05
7: 3930275 44 0.05
...
...
34'000'000:
这是因为每个类别在同一id内多次出现。权重列测量每个类别对专利的分数值(具有2个类别的专利意味着每个类别贡献0.5)。
现在,我想通过简单地在同一行中有一个专利id和多个类(从1到最多20)来减少行数。我想要的是这样的:
id class1 class2 ... class20 weight
1: 3930271 77 0 0 1
2: 3930272 55 654 0 0.5
3: 3930273 65 66 0 0.5
4: 3930274 225 0 0 1
5: 3930275 66 44 30 0.05
6: 3930276 225 33 0 0.5
某些id不会有20个类,因此在这种情况下它应该返回0或点。当类有20个以上的值时,没有选择该类的标准,因为与数百万个id相比,它只发生了几次。
一些专利id将有20多个类,但我想排除这些(很少观察)。
你会怎么做?
我尝试了tidyr的函数spread,但它报告了此错误消息
Error: Each row of output must be identified by a unique combination of keys.
这是因为有时类的值会重复自身,但我需要保持原样。可能有一种更干净的方法来完成此任务。阅读tidyr::spread()和gather()以及data.table::dcast()、melt()和cast() 使用您提供的示例数据:
sample_data <- data.frame("id" = c(3930271, 3930272, 3930272,
3930273, 3930273, 3930274,
3930275, 3930275),
"class" = c(77, 55, 654,
66, 66, 225,
66, 44),
"weight" = c(1, 0.5, 0.5, 0.5,
0.5, 1, 0.05, 0.05))
从列中删除字符向量瑕疵。这将从所有列中删除所有非数字字符!转换回数值并绑定列以返回到dataframe数据结构
wide_df_new <- lapply(wide_df_new , function(x) gsub("[^0-9\\.]", "", x)) %>%
lapply(as.numeric) %>%
bind_cols()
wide\u df\u new%
lappy(作为数值)%>%
bind_cols()
最后但并非最不重要的一点是,用0填充所有NA值
wide_df_new[is.na(wide_df_new)] <- 0
wide_df_new[is.na(wide_df_new)]这里有一个data.table
答案,应该会给出您想要的输出。诀窍是使用data.table
中的特殊符号.N
获取编号,这将以动态方式为类创建所需的序列。这是示例数据,请注意,我将其转换为数据。表
:
library(data.table)
sample_data <- data.table("id" = c(3930271, 3930272, 3930272,
3930273, 3930273, 3930274,
3930275, 3930275),
"class" = c(77, 55, 654,
65, 66, 225,
66, 44),
"weight" = c(1, 0.5, 0.5, 0.5,
0.5, 1, 0.05, 0.05))
库(data.table)
样本数据data.table的另一种方法
library(data.table)
sample_data[, ri := paste0("class",seq_len(.N)), by=.(id, weight)]
ans <- dcast(sample_data[ri<=20], id + weight ~ ri, value.var="class")
ans[, names(ans) := lapply(.SD, function(x) replace(x, is.na(x), 0))]
ans
库(data.table)
样本数据[,ri:=paste0(“类”,序号(.N)),由=(id,重量)]
ans您应该澄清class2
到class20
的逻辑-值从何而来,以及权重如何计算?每个专利id
是否有20个类,或者您是否用0
填充其余部分?有些课程超过20门吗?我编辑了我的问题。你可以使用tidyr::spread()
。问得好。当类有超过20个值时,没有选择类的标准,因为与数百万个id相比,它只发生了几次。坦白说,我宁愿排除那些有超过20个类的id。太好了!你的第一个答复近乎完美。这个回答的唯一问题是,我得到的分数计数权重值错误。第二个报告了一个错误:UseMethod中的错误(“group_by_”):没有适用于“group_by_”的方法应用于类别为“c”(“standardGeneric”、“genericFunction”、“function”、“OptionalFunction”、“PossibleMethod”、“optionalMethod”)“@MatteoTraversini的对象,感谢您的检查。我修改了summary函数调用,以包含权重变量的正确计算。尝试使用库(dplyr)
重新导入dplyr库。可能另一个包正在覆盖环境中的group_by。代码在我的机器上运行时没有错误。@MatteoTraversini如果您希望保留超过20个类值的id,但忽略每个id在20个类值之后的任何值,请删除筛选行并修改单独的函数调用,以包括extra=“drop”
参数。类值和关联列的数量可以通过用于定义新列名称的顺序来控制。我重试了,但权重仍然不起作用。此外,您在数据集中提供的清理NA的方法是世界末日,并将我的数据减少到0。@MatteoTraversini已更改wide_df_new+1。data.table方法的运行速度将明显快于dplyr方法,尤其是3400万行。第三行代码返回此错误:CJ中的错误(1:5866126,1:1109):提供给CJ()的元素的叉积将导致6505533734行超过。Machine$integer.max==2147483647添加了一些内容来尝试解决它。你能分享一些关于你数据的统计数据吗?比如id和权重列中唯一元素的数量?
wide_df_new[is.na(wide_df_new)] <- 0
library(data.table)
sample_data <- data.table("id" = c(3930271, 3930272, 3930272,
3930273, 3930273, 3930274,
3930275, 3930275),
"class" = c(77, 55, 654,
65, 66, 225,
66, 44),
"weight" = c(1, 0.5, 0.5, 0.5,
0.5, 1, 0.05, 0.05))
melt_dt<-sample_data[,melt(.SD,measure.vars=c("class"))]
melt_dt[,id_count:=seq_len(.N),by="id"][id_count<=20][,colname_val:=paste0("class",id_count)]
wide_dt<-dcast(melt_dt,id+weight~colname_val, value.var="value",fill=0)
library(data.table)
sample_data[, ri := paste0("class",seq_len(.N)), by=.(id, weight)]
ans <- dcast(sample_data[ri<=20], id + weight ~ ri, value.var="class")
ans[, names(ans) := lapply(.SD, function(x) replace(x, is.na(x), 0))]
ans