编辑: 好的,所以我使用G.Grothendieck的建议解决了我最初的问题,再次感谢,正是我所追求的干净方式。最初的帖子如下。 现在的事实是我的文件比这个模板更微妙。
实际上看起来像这样:
A1
100
200
txt
A2
STRING
300
400
txt txt
txt
txt txt txt
A3
STRING
STRING
150
250
A2
.
.
.
在某事物之后就知道的STRING,有时它不会发生,有时只发生一次或几次。我一开始并没有注意到几次出现,所以在考虑它只发生一次时,我做了一个循环来处理这个问题:
for (i in 1:nrow(raw_data)){
if (is.na(raw_data[i,2])) {
raw_data <- raw_data[-c(i)]
} else if (raw_data[i,2] == "STRING") {
raw_data[i,2] = raw_data[i,3]
raw_data[i,3] = raw_data[i,4]
raw_data[i,4] = raw_data[i,5]
raw_data[i,5] = raw_data[i,6]
raw_data[i,6] = raw_data[i,7]
raw_data[i,7] = raw_data[i,8]
raw_data[i,8] = raw_data[i,9]
raw_data[i,9] = raw_data[i,10]
raw_data[i,10] = raw_data[i,12]
raw_data[i,11] = "Yes"
if (is.na(raw_data[i,13])){
raw_data[i,12] = NA
} else raw_data[i,12] = raw_data[i,13]
基本上我在第11栏中指定“是”来说明找到了字符串。我显然应该在这里陈述出现而不是是/否(默认为0,1或2或......)。所有其他列值都向左移动,以便它们返回到预期的列。
如果可能的话,我怎样才能适应这样的事实:实际上,我可能会发生几次STRING。我可能要改变我的方法吗?
现在对于那些喜欢挑战的人,我真的开始评估我的处理是否真的对这个文件有效...如何处理原始文件的每一行,因为我们知道像A1这样的东西A2等应该进入col1等...?
无论如何,感谢那些会对此进行调查的人并尝试:)
首发帖子: 我在R中有一个数据集,它由一个包含我想要在多列中的变量的列组成。结构如下:
A1
100
200
txt
A2
300
400
txt txt
txt
txt txt txt
A3
150
250
A2
.
.
.
理想情况下,这是我追逐的结果:
A1 | 100 | 200 | txt
A2 | 300 | 400 | txt txt | txt | txt txt
A3 | 150 | 250
A2 | . | . | .
集合{A1; A2; A3}是已知的。我现在遇到的主要困难是列数是未知的。
我已经开始转置我的数据,并且正在考虑在单行上进行循环,每次我看到我的集合{A1; A2; A3}中的一个值时,我会以此值开始一个新行在第1列中,以便第1列仅包含{A1; A2; A3}值。
我确信有更清洁的方式来完成这项任务。
提前感谢您对此的帮助!
答案 0 :(得分:5)
创建分组变量g
并使用tapply
将数据从长格式转换为列表v
。最后,将v
的每个组件转换为"ts"
个对象,将cbind
个"ts"
对象转换为一起(因为"ts"
个对象可以绑定在一起并自动填充NAs )将结果转换为矩阵m
。将m
转换为data.frame并将type.convert
应用于每列以修复列类型。如果矩阵##
足以作为答案,则可以省略标记为m
的两行。
没有使用任何包裹。
g <- cumsum(DF[[1]] %in% c("A1", "A2", "A3"))
v <- tapply(DF[[1]], g, c, simplify = FALSE)
m <- t(do.call(cbind, lapply(v, ts)))
DFout<- as.data.frame(m, stringsAsFactors = FALSE) ##
DFout[] <- lapply(DFout, type.convert, as.is = TRUE) ##
,并提供:
> DFout
V1 V2 V3 V4 V5 V6
1 A1 100 200 txt <NA> <NA>
2 A2 300 400 txt txt txt txt txt txt
3 A3 150 250 <NA> <NA> <NA>
4 A2 NA NA <NA> <NA> <NA>
注意:可重复形式的输入是:
DF <- structure(list(V1 = c("A1", "100", "200", "txt ", "A2", "300",
"400", "txt txt", "txt", "txt txt txt", "A3", "150", "250", "A2"
)), .Names = "V1", row.names = c(NA, -14L), class = "data.frame")
答案 1 :(得分:2)
另一个想法:
library(dplyr)
library(splitstackshape)
df %>%
group_by(id = cumsum(V1 %in% c("A1", "A2", "A3"))) %>%
summarise(col = toString(V1)) %>%
cSplit('col')
给出了:
# id col_1 col_2 col_3 col_4 col_5 col_6
#1: 1 A1 100 200 txt NA NA
#2: 2 A2 300 400 txt txt txt txt txt txt
#3: 3 A3 150 250 NA NA NA
#4: 4 A2 NA NA NA NA NA
答案 2 :(得分:2)
OP在其他答案发布后编辑了他的问题。因此,这些答案并未意识到"STRING"
偶尔出现的附加复杂性。
以下解决方案解决了此问题,并计算了"STRING"
在删除之前的出现次数。
library(data.table)
setDT(DF)[, rn := cumsum(V1 %like% "^A\\d+")][
, occurrences := sum(V1 == "STRING"), by = rn][
V1 != "STRING",
dcast(.SD, rn + occurrences ~ rowid(rn, prefix = "V"), value.var = "V1")][
, lapply(.SD, function(x) if (is.character(x)) type.convert(x, as.is = TRUE) else x)]
rn occurrences V1 V2 V3 V4 V5 V6 1: 1 0 A1 100 200 txt NA NA 2: 2 1 A2 300 400 txt txt txt txt txt txt 3: 3 2 A3 150 250 NA NA NA 4: 4 0 A2 NA NA NA NA NA
setDF(DF)
强制执行data.table
到位,即无需复制。A
开头,后跟一个或多个数字的行。每个行和所有后续行,直到下一个Axx
获得唯一的组ID。遇到下一个Axx
行时,组ID将提前1. "STRING"
的出现次数。"STRING"
的行后,其余行将使用dcast()
进行重新整形。公式rn + occurrences ~ rowid(rn, prefix = "V")
确定新表的布局。 rn
和occurrences
位于每一行的前面,而每组的行形成列。由于事先不知道每个组中的行数,rowid()
函数用于对每个组中的行进行编号,从而创建新的列名。as.is = TRUE
可以防止角色的因素变为因素。DF <- structure(list(V1 = c("A1", "100", "200", "txt", "A2", "STRING",
"300", "400", "txt txt", "txt", "txt txt txt", "A3", "STRING",
"STRING", "150", "250", "A2")), .Names = "V1", row.names = c(NA,
-17L), class = "data.frame")