请问我想作下面的转换, 代码可以怎么写?
在考试科目和考期之间, 用点号隔开. 我事先知道有哪些科目, 但不知道考期有几次, 比如除了期中, 期末, 还可能有一模, 二模等等.

数据源:
|学生 | 语文.期中 | 数学.期中 | 语文.期末 | 数学.期末|
| 小王 | 90 | 80 | 88 | 92|

目标结构:
学生 考期 语文 数学
小王 期中 90 80
小王 期末 88 92

我想把宽表旋转为长表, 但不会用R语言表达.
我读了pivot_longer()的说明, 可还是不太明白, 十分感谢.

df = data.frame(
  学生  = "小王",
  语文.期中 = 90,
  数学.期中 = 80,
  语文.期末 = 88,
  数学.期末 = 92
)

library(tidyr)
df %>%
  pivot_longer(-学生, names_to = "key", values_to = "得分") %>%
  separate(key, into = c("课程", "考期"), sep = "\\.") %>%
  pivot_wider(names_from =  课程, values_from =  得分)
dat <- data.frame(
  学生 = "小王",
  语文_期中 = 90,
  数学_期中 = 80,
  语文_期末 = 88,
  数学_期末 = 92
)

## data.table version
library(data.table)
library(stringr)
setDT(dat)
dat <- melt(dat, id.vars = "学生", variable.name = "subject_sequence", value.name = "score")
dat[, `:=`(
  考期 = str_split(subject_sequence, "_", simplify = TRUE)[, 2],
  subject = str_split(subject_sequence, "_", simplify = TRUE)[, 1]
)]
dat <- dcast(dat, 学生 + 考期 ~ subject, value.var = "score")

## tidyr version
library(tidyr)
dat <- as_tibble(dat)
dat %>% 
  pivot_longer(cols = !学生, names_sep = "_", names_to = c("subject", "考期")) %>% 
  pivot_wider(names_from = "subject", values_from = "value")

虽然tidyr写起来更简洁,但是我还是觉得data.table更好。上一次用tidyr我记得这两个函数还是叫gather()spread()来着。

    FangGong 两位大佬不约而同结合使用了pivot_longer()和pivot_wider(), 受教了. 只是data.table 版的quote:=quote 对我而言已经接近黑魔法了.

    5 天 后
    dat <- data.frame(
      学生 = c("小王", "小张"),
      语文_期中 = c(90, 89),
      数学_期中 = c(80, 81),
      语文_期末 = c(88, 87),
      数学_期末 = c(92, 93)
    )
    
    dat
    #>   学生 语文_期中 数学_期中 语文_期末 数学_期末
    #> 1 小王     90       80       88        92
    #> 2 小张     89       81       87        93
    
    dat <- reshape(
        dat,
        direction = "long",
        idvar = "学生",
        timevar = "科目_考期",
        times = colnames(dat)[-1],
        v.names = "分数",
        varying = list(2:5)
      )
    rownames(dat) <- NULL
    
    dat
    #>   学生 科目_考期 分数
    #> 1 小王 语文_期中   90
    #> 2 小张 语文_期中   89
    #> 3 小王 数学_期中   80
    #> 4 小张 数学_期中   81
    #> 5 小王 语文_期末   88
    #> 6 小张 语文_期末   87
    #> 7 小王 数学_期末   92
    #> 8 小张 数学_期末   93
    
    dat[, c("科目", "考期")] <- read.table(text = dat$科目_考期, sep = "_")
    dat[, "科目_考期"] <- NULL
    
    
    dat <- reshape(
      dat,
      direction = "wide",
      idvar = c("学生", "考期"),
      timevar = "科目",
      sep = "_"
    )
    
    dat
    #>   学生 考期 分数_语文 分数_数学
    #> 1 小王 期中      90       80
    #> 2 小张 期中      89       81
    #> 5 小王 期末      88       92
    #> 6 小张 期末      87       93

    <sup>Created on 2021-10-09 by the reprex package (v2.0.0)</sup>