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