在BASE R中操作data.frame格式

在BASE R中操作data.frame格式,r,dataframe,R,Dataframe,我已经看到了给出的答案,但我想知道在我的情况下,是否有一种有效的方法可以在BASE R中将我的输入data.frame更改为下面所示的所需输出data.frame input <- data.frame(id = c(1,3,6), school = LETTERS[1:3], read_1 = c(20,22,24), read_1_sp = c(T,F,T), read_2 =c(45,47,49),read_2_sp = c(F,F,F),

我已经看到了给出的答案,但我想知道在我的情况下,是否有一种有效的方法可以在BASE R中将我的
输入
data.frame更改为下面所示的所需
输出
data.frame

input <- data.frame(id = c(1,3,6), school = LETTERS[1:3], read_1 = c(20,22,24),
               read_1_sp = c(T,F,T), read_2 =c(45,47,49),read_2_sp = c(F,F,F),  
               math_1 =c(20,22,NA), math_1_sp = c(T,F,NA), math_2 = c(NA,35,37),
               math_2_sp =c(NA,F,F))


output <- data.frame(id = c(rep(1,3),rep(3,4), rep(6, 3)),school = c(rep("A",3),rep("B",4), rep("C", 3)),   
                      subject = c("read","read","math","read","read","math", "math","read","read","math"),  
                      no.= c(1,2,1,1,2,1,2,1,2,2), score = c(20,45,20,22,47,22,35,24,49,37),    
                      sp = c(T,F,T,T,F,T,T,T,F,T))
input1)基本-重塑创建两个元素的列表,
变化
,每个元素都是名称的字符向量——第一个元素是
分数
名称的向量,第二个元素是
sp
名称的向量。将其与基础一起使用
重塑
。然后按
idvar
变量排序(如果不需要,则省略执行排序的两行),并使用
na删除带有NAs的行。省略
<代码>重塑
生成一个
主题
列,其中包含
read_1
等条目。transform语句将其拆分为两列,
subject
no

varying <- lapply(c("\\d$", "sp$"), grep, names(input), value = TRUE)

r <- reshape(input, dir = "long", idvar = c("id", "school"), 
  varying = varying, v.names = c("score", "sp"),
  times = varying[[1]], timevar = "subject")  

o <- with(r, order(id, school))
r <- r[o, ]
r <- na.omit(r)

transform(r, subject = sub("_.*", "", subject), no = as.numeric(sub(".*_", "", subject)))
2)data.table-melt问题要求基本解决方案,但为了进行比较,我们还在data.table中显示了使用
melt
的解决方案

input
转换为data.table,并使用键和指示的模式将其熔化
melt
REFORMATE
中的
时间=
没有对应项,而是在
变量.name
列中提供索引号,在本例中,该列为
主题。我们使用它来索引
时间
。这会产生诸如
read_1
之类的元素,因此我们使用
fread
subject
分为两列,
subject
no
。最后,使用
na删除具有NAs的行。省略
并通过指定键进行排序

library(data.table)

input2 <- as.data.table(input, key = c("id", "school"))
times <- grep("\\d$", names(input2), value = TRUE)  # score col names

melt(input2, measure = patterns(sp = "sp", score = "\\d$"), variable.name = "subject")[, 
  c("subject", "no"):= fread(text = times[subject], sep = "_")][, 
  na.omit(.SD), key = key(input2)]
1)基本-重塑创建两个元素的列表,每个元素都是名称的字符向量,第一个元素是
分数
名称的向量,第二个元素是
sp
名称的向量。将其与基础一起使用
重塑
。然后按
idvar
变量排序(如果不需要,则省略执行排序的两行),并使用
na删除带有NAs的行。省略
<代码>重塑
生成一个
主题
列,其中包含
read_1
等条目。transform语句将其拆分为两列,
subject
no

varying <- lapply(c("\\d$", "sp$"), grep, names(input), value = TRUE)

r <- reshape(input, dir = "long", idvar = c("id", "school"), 
  varying = varying, v.names = c("score", "sp"),
  times = varying[[1]], timevar = "subject")  

o <- with(r, order(id, school))
r <- r[o, ]
r <- na.omit(r)

transform(r, subject = sub("_.*", "", subject), no = as.numeric(sub(".*_", "", subject)))
2)data.table-melt问题要求基本解决方案,但为了进行比较,我们还在data.table中显示了使用
melt
的解决方案

input
转换为data.table,并使用键和指示的模式将其熔化
melt
REFORMATE
中的
时间=
没有对应项,而是在
变量.name
列中提供索引号,在本例中,该列为
主题。我们使用它来索引
时间
。这会产生诸如
read_1
之类的元素,因此我们使用
fread
subject
分为两列,
subject
no
。最后,使用
na删除具有NAs的行。省略
并通过指定键进行排序

library(data.table)

input2 <- as.data.table(input, key = c("id", "school"))
times <- grep("\\d$", names(input2), value = TRUE)  # score col names

melt(input2, measure = patterns(sp = "sp", score = "\\d$"), variable.name = "subject")[, 
  c("subject", "no"):= fread(text = times[subject], sep = "_")][, 
  na.omit(.SD), key = key(input2)]

tidyverse
中,我们可以

library(tidyr)
library(stringr)
input %>%
   rename_at(vars(matches('\\d+$')), ~ str_c(., '_score')) %>%
   pivot_longer(cols = -c(id, school), names_to = c('subject', 'no', '.value'),
          names_sep="_", values_drop_na = TRUE)
# A tibble: 10 x 6
#      id school subject no    score sp   
#   <dbl> <fct>  <chr>   <chr> <dbl> <lgl>
# 1     1 A      read    1        20 TRUE 
# 2     1 A      read    2        45 FALSE
# 3     1 A      math    1        20 TRUE 
# 4     3 B      read    1        22 FALSE
# 5     3 B      read    2        47 FALSE
# 6     3 B      math    1        22 FALSE
# 7     3 B      math    2        35 FALSE
# 8     6 C      read    1        24 TRUE 
# 9     6 C      read    2        49 FALSE
#10     6 C      math    2        37 FALSE

tidyverse
中,我们可以

library(tidyr)
library(stringr)
input %>%
   rename_at(vars(matches('\\d+$')), ~ str_c(., '_score')) %>%
   pivot_longer(cols = -c(id, school), names_to = c('subject', 'no', '.value'),
          names_sep="_", values_drop_na = TRUE)
# A tibble: 10 x 6
#      id school subject no    score sp   
#   <dbl> <fct>  <chr>   <chr> <dbl> <lgl>
# 1     1 A      read    1        20 TRUE 
# 2     1 A      read    2        45 FALSE
# 3     1 A      math    1        20 TRUE 
# 4     3 B      read    1        22 FALSE
# 5     3 B      read    2        47 FALSE
# 6     3 B      math    1        22 FALSE
# 7     3 B      math    2        35 FALSE
# 8     6 C      read    1        24 TRUE 
# 9     6 C      read    2        49 FALSE
#10     6 C      math    2        37 FALSE

您是否尝试过
stats::重塑
?这不是最直观的处理方法,但它可以实现您所寻求的重塑。由于您试图缩小几个列,我怀疑将需要几个独立的调用来
重塑
,然后
合并
它们。在我看来,这是
tidyr::pivot\u longer
的强大动力。。。虽然我很欣赏你坚持使用base R的动机,但便利功能之所以如此重要是有原因的。。。便利性:-)您是否考虑过
sqldf
或其他基于sql的解决方案?这与您的base-R约束相反,但是如果您已经在工作流的其他地方使用了
sqldf
DBI
RSQLite
,或者其他一些DBMS,您可以利用它。您是否尝试过
stats::restrape
?这不是最直观的处理方法,但它可以实现您所寻求的重塑。由于您试图缩小几个列,我怀疑将需要几个独立的调用来
重塑
,然后
合并
它们。在我看来,这是
tidyr::pivot\u longer
的强大动力。。。虽然我很欣赏你坚持使用base R的动机,但便利功能之所以如此重要是有原因的。。。便利性:-)您是否考虑过
sqldf
或其他基于sql的解决方案?这与您的base-R约束相反,但是如果您已经使用了
sqldf
DBI
RSQLite
,或者工作流中的其他一些DBMS,您可以利用它。@rnorouzian我添加了一个
base R
。@rnorouzian我删除了该解决方案,因为它可以收集一些dvs。不管怎样,你有另一个解决方案,是在基地工作R@Reza我将重塑更改为拆分,因为已经有一个解决方案。@rnorouzian我添加了一个
base R
@rnorouzian我删除了该解决方案,因为它可以收集一些DV。不管怎样,你有另一个解决方案,是在基地工作R@Reza我将重塑更改为拆分,因为已经有解决方案。稍微简化(1)并添加(2)。稍微简化(1)并添加(2)。