转换tidyverse行操作到数据.表解决方案

u7up0aaq  于 2022-12-20  发布在  其他
关注(0)|答案(1)|浏览(115)

我有一个包含数百万行和数十列的 Dataframe ,我需要对它进行行操作。我下面的解决方案使用dplyr,但我希望切换到data.table可以加快速度。如果您能帮助我将下面的代码转换为data.table版本,我将不胜感激。

library(tidyverse)
library(trend)
 
df = structure(list(id = 1:2, var = c(3L, 9L), col1_x = c("[(1,2,3)]", 
                                                              "[(100,90,80,70,60,50,40,30,20)]"), col2_x = c("[(2,4,6)]", "[(100,50,25,12,6,3,1,1,1)]"
                                                              )), class = "data.frame", row.names = c(NA, -2L))

df  = df %>%
  mutate(across(ends_with("x"),~ gsub("[][()]", "", .)))

x_cols = df  %>% 
  select(ends_with("x")) %>% 
  names()

df  = df %>% 
  rowwise()  %>% 
  mutate(across(all_of(x_cols) ,~  ifelse(var<=4,0,sens.slope(as.numeric(unlist(strsplit(., ','))))$estimates[[1]]),.)) %>%
  ungroup()
cygmwpex

cygmwpex1#

虽然“里奇萨克拉门托写的绝对是真的,但这是你要的信息。
首先,我想从set:=开始。当看到关键字set时(可以只是函数名的 * 部分 *)或:=符号,您已经告诉data.table不要复制数据。(那个讨厌的=<-),你已经改变了数据表,这是防止这个包浪费内存的关键方法之一。
请记住,RStudio中的环境窗格会在注册该操作符(=<-)时触发更新,创建新的内容。由于您执行了替换,环境窗格可能会反映不正确的信息。您可以使用refresh图标(窗格右上角),或者您可以将对象打印到控制台进行检查。
只要声明窗格标识的任何内容,窗格中的所有内容都会更新。
将数据框更改为data.table。(注意关键字-set!)这两个命令的作用是相同的。但是,其中一个命令复制内存中的所有内容,然后重新创建。(将帧命名为相同的名称并不能防止复制。)

setDT(df)

df <- data.table(df)

我不会从你的第一个代码简介开始,我会从名字提取开始。
你写道:

x_cols = df  %>% 
  select(ends_with("x")) %>% 
  names()
# [1] "col1_x" "col2_x"

有很多方法可以得到这些信息,这就是我所做的,注意这和data.table没有任何关系,我只是用了R,你也可以用同样的方法使用 Dataframe 。

xcols <- names(df)[endsWith(names(df), 'x')]
# [1] "col1_x" "col2_x"

我将在剩下的例子中使用这个对象xcols(为什么要重复相同的声明呢?)
您编写以下代码是为了删除方括号和圆括号。

df = df %>%
  mutate(across(ends_with("x"),~ gsub("[][()]", "", .)))
#   id var                      col1_x                 col2_x
# 1  1   3                       1,2,3                  2,4,6
# 2  2   9 100,90,80,70,60,50,40,30,20 100,50,25,12,6,3,1,1,1

有几种方法可以做到这一点,无论是在 Dataframe 还是在data.table中。下面是两个可以用于data.table的方法。它们的作用完全相同,也与您的代码相同。
注意:=,它意味着表发生了变化。我使用了.SD.SDcols。这是数据列选择工具。如果要使用多个列,请使用.SD代替列名。然后使用.SDcols告诉data.table要使用的列。通过对(xcols)进行注解,其中xcols是表示要使用的列名的变量,它告诉data.table替换用于聚合的列中的数据。
这两个函数的区别在于我是如何使用lapply的,这与data.table没有任何关系。如果你需要更多关于这个函数的信息,你可以问我,或者你可以浏览已经存在的许多问答。

df[, 
   (xcols) := lapply(.SD, function(k) gsub("[][()]", "", k)),
   .SDcols = xcols]

df[,
   (xcols) := lapply(.SD, gsub, pattern = "[][()]", 
                     replacement = ""),
   .SDcols = xcols]

您上次的请求就是基于此代码。

df %>% 
  rowwise()  %>% 
  mutate(across(all_of(x_cols),
                ~ifelse(var <= 5, 0, sens.slope(
                  as.numeric(unlist(
                    strsplit(., ','))))$estimates[[1]]),.)) %>%
  ungroup()

由于您使用var来描述何时应用此功能,因此我使用了by参数(如dplyrgroup_by)。关于其他需求,您将再次看到.SDlapply

df[,
   (xcols) := lapply(.SD, 
          function(k) {
            ifelse(var <= 3, 0, 
                   sens.slope(as.numeric(strsplit(k, ",")[[1]])
                   )$estimates[[1]])
          }), by = var, .SDcols = xcols]

如果你想一想它们之间的区别,你会发现,在很多方面,它们并没有那么大的不同。例如,在最后一个 * 翻译 * 中,你会看到我在dplyr中使用的类似方法。

df %>% group_by(var) %>% 
  mutate(across(all_of(x_cols),
                ~ifelse(var <= 5, 0, sens.slope(
                  as.numeric(unlist(
                    strsplit(., ','))))$estimates[[1]])))

相关问题