如何使用R将值动态插入数据帧
在从一个网站上抓取了一些评论数据之后,我很难将这些数据组织成一个有用的结构进行分析。问题在于,数据是动态的,因为每位评审员对0到3个子类别(表示为子类别“a”、“b”和“c”)进行评分。我想组织评审,使每一行都是不同的评审员,而每一列都是一个子类别。如果评审员选择不给子类别评分,我希望缺失的数据为“NA”。以下是数据的简化示例:如何使用R将值动态插入数据帧,r,dataframe,R,Dataframe,在从一个网站上抓取了一些评论数据之后,我很难将这些数据组织成一个有用的结构进行分析。问题在于,数据是动态的,因为每位评审员对0到3个子类别(表示为子类别“a”、“b”和“c”)进行评分。我想组织评审,使每一行都是不同的评审员,而每一列都是一个子类别。如果评审员选择不给子类别评分,我希望缺失的数据为“NA”。以下是数据的简化示例: vec <- c("a","b","c","stop", "a","b","stop", "stop", "c","stop") ratings <- c(
vec <- c("a","b","c","stop", "a","b","stop", "stop", "c","stop")
ratings <- c(2,5,1, 1,3, 2)
vec@alexis_laz提供了我认为最好的答案:
vec <- c("a","b","c","stop", "a","b","stop", "stop", "c","stop")
ratings <- c(2,5,1, 1,3, 2)
stops <- vec == "stop"
i = cumsum(stops)[!stops] + 1L
j = vec[!stops]
tapply(ratings, list(factor(i, 1:max(i)), factor(j)), identity) # although mean/sum work
# a b c
#[1,] 2 5 1
#[2,] 1 3 NA
#[3,] NA NA NA
#[4,] NA NA 2
vec这里有一个选项
library(data.table)
library(reshape2)
d1 <- as.data.table(melt(split(vec, c(1, head(cumsum(vec == "stop")+1,
-1)))))[value != 'stop', ratings := ratings
][value != 'stop'][, value := as.character(value)][, L1 := as.integer(L1)]
dcast( d1[CJ(value = value, L1 = seq_len(max(L1)), unique = TRUE), on = .(value, L1)],
L1 ~value, value.var = 'ratings')[, L1 := NULL][]
# a b c
#1: 2 5 1
#2: 1 3 NA
#3: NA NA NA
#4: NA NA 2
库(data.table)
图书馆(E2)
d1使用基本R函数和rbind.fill
从plyr
或rbindlist
从data.table
生成最终对象,我们可以
# convert vec into a list, split by "stop", dropping final element
temp <- head(strsplit(readLines(textConnection(paste(gsub("stop", "\n", vec, fixed=TRUE),
collapse=" "))), split=" "), -1)
# remove empty strings, but maintain empty list elements
temp <- lapply(temp, function(x) x[nchar(x) > 0])
# match up appropriate names to the individual elements in the list with setNames
# convert vectors to single row data.frames
temp <- Map(function(x, y) setNames(as.data.frame.list(x), y),
relist(ratings, skeleton = temp), temp)
# add silly data.frame (single row, single column) for any empty data.frames in list
temp <- lapply(temp, function(x) if(nrow(x) > 0) x else setNames(data.frame(NA), vec[1]))
请注意,rbind
ing前面的行可以替换为
temp[lengths(temp) == 0] <- replicate(sum(lengths(temp) == 0),
setNames(data.frame(NA), vec[1]), simplify=FALSE)
temp[length(temp)==0]base R,但我使用的是for循环
vec <- c("a","b","c","stop", "a","b","stop", "stop", "c","stop")
ratings <- c(2,5,1, 1,3, 2)
categories <- unique(vec)[unique(vec)!="stop"]
row = 1
df = data.frame(lapply(categories, function(x){NA_integer_}))
colnames(df) <- categories
rating = 1
for(i in vec) {
if(i=='stop') {row <- row+1
} else { df[row,i] <- ratings[[rating]]; rating <- rating+1}
}
vec这里唯一的问题是你错过了第三位评审员的预期输出数据,他没有给出任何评分。@EvanFriedland Good call。我错过了。添加了一个额外的行来修复这个问题。一个有趣的选项是relist
,我在删除累积的重复项时,重复了您先前给出的答案。这是一个非常酷的概念,你可以使用骨架参数来匹配另一个对象的结构,同时用新材料填充它。如果你事先知道“a”、“b”、“c”,这是一个非常好的选择。我想我们可以使用unique(vec)
来构建和填充df
,修改了答案,这样你就不需要知道或明确指定类别。我不是OP,但我给你+1是因为我喜欢:)我相信这个逻辑的更清晰版本可以是stops=vec==“stop”;i=累计(停止)[!停止]+1L;j=向量[!停止];tapply(评级,列表(因子(i,1:max(i)),因子(j)),标识)
?这是难以置信的简洁,我自己也不熟悉tapply标识的使用。我认为你的评论显然是个赢家。
vec <- c("a","b","c","stop", "a","b","stop", "stop", "c","stop")
ratings <- c(2,5,1, 1,3, 2)
categories <- unique(vec)[unique(vec)!="stop"]
row = 1
df = data.frame(lapply(categories, function(x){NA_integer_}))
colnames(df) <- categories
rating = 1
for(i in vec) {
if(i=='stop') {row <- row+1
} else { df[row,i] <- ratings[[rating]]; rating <- rating+1}
}