Re: [问题] dataframe字串切割

楼主: celestialgod (天)   2018-06-06 20:27:43
※ 引述《wmj10054039 (MJ)》之铭言:
: ※ 引述《celestialgod (天)》之铭言:
: : 程式:
: : library(data.table)
: : library(pipeR)
: : library(stringr)
: : dataStr <- "流水号 课程名称 时间 地点 人数
: : 102 A 二3,4四5,7 甲 10
: : 248 B 一1,2,3 乙 20
: : 314 C 三4五7,8,a 丙 5"
: : removeEmptyFunc <- function(x) x[nchar(x) > 0]
: : fread(dataStr) %>>%
: : `[`(j = `:=`(星期 = str_split(时间, "[a-zA-Z0-9,]+") %>>%
: : lapply(removeEmptyFunc),
: : 节次 = str_split(时间, "[^a-zA-Z0-9,]+") %>>%
: : lapply(removeEmptyFunc))) %>>%
: : `[`(j = .(星期 = unlist(星期), 节次 = unlist(节次)),
: : by = .(流水号, 课程名称, 地点, 人数)) %>>%
: : `[`(j = `:=`(节次 = str_split(节次, ","))) %>>%
: : `[`(j = .(节次 = unlist(节次)), by = .(流水号, 课程名称, 地点, 人数, 星期))
: : ## no pipe 程式码
: : dataDT <- fread(dataStr)
: : dataDT[ , `:=`(星期 = lapply(str_split(时间, "[a-zA-Z0-9,]+"),
: : removeEmptyFunc),
: : 节次 = lapply(str_split(时间, "[^a-zA-Z0-9,]+"),
: : removeEmptyFunc))]
: : tmpDT <- dataDT[ , .(星期 = unlist(星期), 节次 = unlist(节次)),
: : by = .(流水号, 课程名称, 地点, 人数)]
: : tmpDT[ , `:=`(节次 = str_split(节次, ","))]
: : tmpDT[ , .(节次 = unlist(节次)), by = .(流水号, 课程名称, 地点, 人数, 星期)]
: : 结果:
: : # 流水号 课程名称 地点 人数 星期 节次
: : # 1: 102 A 甲 10 二 3
: : # 2: 102 A 甲 10 二 4
: : # 3: 102 A 甲 10 四 5
: : # 4: 102 A 甲 10 四 7
: : # 5: 248 B 乙 20 一 1
: : # 6: 248 B 乙 20 一 2
: : # 7: 248 B 乙 20 一 3
: : # 8: 314 C 丙 5 三 4
: : # 9: 314 C 丙 5 五 7
: : # 10: 314 C 丙 5 五 8
: : # 11: 314 C 丙 5 五 a
: 我在回应区的问题是想要把如果节次包含3节以上的课程,只取出头跟尾的节次,并且只有
: 一节课的课程重复两次,也就是说每个课程重复在dataframe的次数都会是偶数倍(主要
: 目的是想知道每个时段下不同地点会产生的进出人数),举例来说:
: 流水号 课程名称 时间 人数 地点
: 102 A 二3,4四5,7 10 甲
: 248 B 一1,2,3 20 乙
: 314 C 三4五7,8,a 5 丙
: 整理成
: 流水号 课程名称 地点 人数 星期 节次
: 102 A 甲 10 二 3
: 102 A 甲 10 二 4
: . .
: . .
: . .
: 248 B 乙 20 一 1
: 248 B 乙 20 一 3
: 314 C 丙 5 三 4
: 314 C 丙 5 三 4
: 314 C 丙 5 五 7
: 314 C 丙 5 五 a
: 我目前的想法是利用c大处理我之前问题的方法,将已经把时间拆开成星期跟节次但
: 还没unlist的节次取出,用循环搭配条件判断存成新的list再放回data.frame,但发现
: 这个方法存成的list只会有最后一个元素有值,其他都是NULL。想请教是哪边有错误,
: 或是有更好的解决方法,谢谢。
: [程式范例]
: oldlist = df$节次
: newlist = list()
: for (i in length(oldlist)) {
: if (length(oldlist[[i]]) == 1){
: newlist[[i]] = rep(oldlist[[i]][1], 2)
: }else if (length(oldlist[[i]]) == 2){
: newlist[[i]] = c(oldlist[[i]][1], oldlist[[i]][2])
: }else if (length(oldlist[[i]]) == 3){
: newlist[[i]] = c(oldlist[[i]][1], olslist[[i]][3])
: }
: }
直接用原本整理好的data.table在整理一下就好了
(outDT是前次的输出)
# 先转成factor (节次为1~8 然后接A~E,如果不对再自行调整)
# 这样会转成整数比较好做
outDT[ , 节次 := factor(节次, c(1:8, letters[1:5]))]
# 用diff找出前后都相差1的节次还把它们移除掉
outDT[ , filter := diff(c(-2, 节次)) == 1 & diff(c(节次, 20)) == 1,
by = .(流水号, 课程名称, 地点, 人数, 星期)]
# 过滤掉前后都相差1的节次
finalDT <- outDT[filter == FALSE]
# 把filter这个字段移除掉
finalDT[ , filter := NULL]
# 最后:
# 流水号 课程名称 地点 人数 星期 节次
# 1: 102 A 甲 10 二 3
# 2: 102 A 甲 10 二 4
# 3: 102 A 甲 10 四 5
# 4: 102 A 甲 10 四 7
# 5: 248 B 乙 20 一 1
# 6: 248 B 乙 20 一 3
# 7: 314 C 丙 5 三 4
# 8: 314 C 丙 5 五 7
# 9: 314 C 丙 5 五 a
作者: wmj10054039 (MJ)   2018-06-07 20:54:00
感谢C大和Wush大 ~~收益良多!

Links booklink

Contact Us: admin [ a t ] ucptt.com