Re: [问题] 资料转换

楼主: celestialgod (天)   2015-11-15 14:16:38
关于使用循环,我有一点想法可以参考看看
最下方补上不用for-loop的方法
# data generation
set.seed(300)
N = 100
df = data.frame(x = sample(1:100, N, TRUE), y = runif(N),
z = sample(0:1, N, TRUE, prob = c(0.4, 0.6)))
# 计算重复的长度,已取得我需要preallocate多大的矩阵
zLength = rle(df$z)$lengths
# zLength:
# [1] 4 3 1 1 2 1 2 1 1 2 2 1 4 3 1 1 2 1 1 2 1 3 1 2
# [25] 1 3 1 3 1 2 2 2 1 2 1 2 2 5 4 2 10 3 2 1 1 2 2 2
# 超过五的部分都要多加一行
outRow = length(zLength) + zLength[zLength > 5] %/% 5 +
as.numeric(zLength[(zLength > 5)] %% 5 > 0) - sum(zLength > 5)
# outRow:
# [1] 49 (只有一个超过5,只需要多一行)
# create output matrix and preallocate
outMat = matrix(NA, outRow, 5)
# 上一个值
lastValue = 1 - df$z[1]
j = 0 # row编号
k = 0 # col编号
rowNamesVec = vector('numeric', outRow) # 存rownames
for (i in 1:nrow(df))
{
if (df$z[i] != lastValue) # 如果跟上一个值不相同就跑这块
{
j = j + 1 # 移到下一个row
k = 1 # col回到1 (新的row)
outMat[j, k] = df$x[i] # assign进去output的matrix
lastValue = df$z[i] # 把这次的z存起来做下一次的判断
rowNamesVec[j] = df$z[i] # 存下这次的z以assign rownames
}
else # 如果跟上一个值相同就跑这块
{
k = k + 1 # 移到下一个column
if (k > 5) # 如果k超过五就移到下一个row 并且存进rownames
{
j = j + 1
k = 1
rowNamesVec[j] = df$z[i]
}
outMat[j, k] = df$x[i] # assign进去output的matrix
}
}
rownames(outMat) = rowNamesVec # 赋予rownames
outMat结果:
[,1] [,2] [,3] [,4] [,5]
0 92 77 81 74 NA
1 69 2 76 NA NA
0 50 NA NA NA NA
1 47 NA NA NA NA
0 91 95 NA NA NA
1 32 NA NA NA NA
0 80 59 NA NA NA
1 66 NA NA NA NA
0 99 NA NA NA NA
1 89 67 NA NA NA
0 64 51 NA NA NA
1 99 NA NA NA NA
0 50 47 7 10 NA
1 3 53 90 NA NA
0 70 NA NA NA NA
1 23 NA NA NA NA
0 52 72 NA NA NA
1 93 NA NA NA NA
0 39 NA NA NA NA
1 10 46 NA NA NA
0 40 NA NA NA NA
1 76 62 78 NA NA
0 37 NA NA NA NA
1 1 74 NA NA NA
0 88 NA NA NA NA
1 38 87 56 NA NA
0 35 NA NA NA NA
1 13 75 38 NA NA
0 80 NA NA NA NA
1 60 100 NA NA NA
0 91 59 NA NA NA
1 47 89 NA NA NA
0 86 NA NA NA NA
1 5 37 NA NA NA
0 63 NA NA NA NA
1 65 30 NA NA NA
0 22 60 NA NA NA
1 44 52 79 78 64
0 86 25 7 51 NA
1 31 42 NA NA NA
0 92 13 68 82 19
0 21 95 42 24 66
1 67 91 44 NA NA
0 92 31 NA NA NA
1 84 NA NA NA NA
0 52 NA NA NA NA
1 75 40 NA NA NA
0 68 17 NA NA NA
1 60 20 NA NA NA
## no for loop
continueLength = rle(df$z)$lengths
splitGroup = rep(1:length(continueLength), continueLength)
outMat = lapply(split(df, splitGroup), function(subdf){
if (length(subdf$x) <= 5)
c(subdf$x, rep(NA, 5 - length(subdf$x)))
else
{
numRows = length(subdf$x) %/% 5 + as.numeric(length(subdf$x) %% 5 > 0)
NAnum = 5 - length(subdf$x)%%5
matrix(c(subdf$x,rep(NA,NAnum)), numRows, 5, byrow = TRUE)
}
})
outMat = do.call(rbind, outMat)
rownames(outMat)[nchar(rownames(outMat)) != 0] = rle(df$z)$values
※ 引述《Rose9305 (台产零零柒)》之铭言:
: [问题类型]:
: 程式咨询(我想用R 做某件事情,但是我不知道要怎么用R 写出来)
: [软件熟悉度]:
: 新手(没写过程式,R 是我的第一次)
: [问题叙述]:
: 资料转换
: 我有个资料csv档,里面内容大概如下 :
: x y z
: 55 0.2 1
: 44 0.6 1
: 78 0.7 0
: 46 0.8 0
: 98 0.9 1
: 47 0.4 1
: 46 0.5 1
: 想(限)用 ''for 循环''转换成只取x,z并以z重排x,如下:
: 1 55 44
: 0 78 46
: 1 98 47 46
: 把 z=1 排成一列,一遇到 z=0 又排成一列,再读到1又排成一列这样下去
: 不知道要如何用for循环来把资料转换成上述。
: 抱歉,再问下因实际DATA比较多,因此可以每列只列5个值然后换下一行吗?
: 一样用1,0排,
: 像是 1 55 44 67 78 46
: 1 47 48 99 78 16
: 0 48 49 77 66 55
: 1 76 78 79 88 99 这样排列呢??

Links booklink

Contact Us: admin [ a t ] ucptt.com