【问题标题】:Is There A Neat/Simplest Way To This data.table R Code?这个data.table R代码有一个简洁/最简单的方法吗?
【发布时间】:2020-04-25 14:11:55
【问题描述】:

来自 OECD 数据的 STRATUM 太长了,为了简单起见,我把它命名为更短和更精确的名称,如下面的代码所示。

pisaMas[,`:=`
             (SchoolType = c(ifelse(STRATUM == "National Secondary School", "Public", 
                                    ifelse(STRATUM == "Religious School", "Religious", 
                                           ifelse(STRATUM == "MOE Technical School", "Technical",0)))))]
pisaMas[,table(SchoolType)]

我想知道是否有一个简单的方法来解决这个问题,使用 data.table 包。

【问题讨论】:

  • 我将创建一个两列数据框,其中一列中的长名称和另一列中的短名称,然后合并长名称,然后删除长名称列,保留短名称列。您唯一需要做的就是确保在新数据框的 BOTH 列中对不想替换的名称使用长名称列名称,这样就不会删除它们或引入 NA 值。
  • 是的,连接是 data.table 的方法。

标签: r if-statement data.table rename gsub


【解决方案1】:

这是我经过思考后得出的结论。

#' First I create a function (rname.SchType) that have oldname and newname using else if:

rname.SchType <- function(x){
  if (is.na(x)) NA
  else if (x == "MYS - stratum 01: MOE National Secondary School\\Other States")"Public"
  else if(x == "MYS - stratum 02: MOE Religious School\\Other States")"Religious" 
  else if(x == "MYS - stratum 03: MOE Technical School\\Other States")"Technical"
  else if(x == "MYS - stratum 04: MOE Fully Residential School")"SBP"
  else if(x == "MYS - stratum 05: non-MOE MARA Junior Science College\\Other States")"MARA"
  else if(x == "MYS - stratum 06: non-MOE Other Schools\\Other States")"Private"
  else if(x == "MYS - stratum 07: Perlis non-“MOE Fully Residential Schools”")"Perlis Fully Residential"
  else if(x == "MYS - stratum 08: Wilayah Persekutuan Putrajaya non-“MOE Fully Residential Schools”")"Putrajaya Fully Residential"
  else if(x == "MYS - stratum 09: Wilayah Persekutuan Labuan non-“MOE Fully Residential Schools”")"Labuan Fully Residential"
}

通过使用我刚刚创建的函数,我通过在 data.table 中应用 base R (sapply) 只用一行代码将它通过 data.table,因此设法避免代码混乱并且看起来更简单:

pisaMalaysia[,`:=`(jenisSekolah = sapply(STRATUM,rname.SchType))]

【讨论】:

  • 可能更简单(在您看来!)但效率极低。
  • 因为它没有矢量化。当您可以使用 C 级循环时,您正在使用 R 级循环。
  • 谢谢@Roland!这对我来说是全新的知识。之前对C级和R级的区别一无所知。我会调查的!
【解决方案2】:

data.table的当前开发版本针对这种情况有新功能fcase(仿照SQLCASE WHEN):

pisaMas[ , SchoolType := fcase(
  STRATUM == "National Secondary School", "Public", 
  STRATUM == "Religious School", "Religious", 
  STRATUM == "MOE Technical School", "Technical",
  default = ''
)]
pisaMas[ , table(SchoolType)]

要获取开发版本,请尝试

install.packages(
  'data.table', type = 'source',repos = 'http://Rdatatable.github.io/data.table'
)

如果简单安装不起作用,您可以查看安装 wiki 了解更多详细信息:

https://github.com/Rdatatable/data.table/wiki/Installation

您也可以使用查找表来解决此问题,详情请参阅此问答:

https://stackoverflow.com/a/36391018/3576984

【讨论】:

  • 有趣!谢谢。这是解决这个问题的一种很酷的方法。我真的需要把默认 = ' ' 吗?为什么?
  • @ZeeA。你可以随心所欲地制作default。如果不指定,则为default = NA_character_
  • 不幸的是,我花了一整天的时间按照网上的所有说明来弄清楚如何使用 fcase,但似乎失败了很多错误。从删除软件包开始,然后使用“源”重新安装。
  • @ZeeA。不好了!很遗憾听到这个消息。如果您可以提炼问题,您可以在 GitHub 上提交可用性请求。或者,如果您不确定,可以尝试针对fcase 提出一个新问题。
【解决方案3】:

我想我终于得到了上述问题的答案!这个答案克服了@Roland 提到的“未矢量化”的问题,谢谢先生!在我看来,它要快得多,尽管我花了几个星期才理解这个概念并在网上找到正确的问题!

首先,我创建一个新的 data.table,其中包含 2 列,其中一个具有原始名称,第二个是学校的所需名称。

lookUpStratum <- data.table(STRATUM=c("MYS - stratum 01: MOE National Secondary School\\Other States",
                                      "MYS - stratum 02: MOE Religious School\\Other States",
                                      "MYS - stratum 03: MOE Technical School\\Other States",
                                      "MYS - stratum 04: MOE Fully Residential School",
                                      "MYS - stratum 05: non-MOE MARA Junior Science College\\Other States",
                                      "MYS - stratum 06: non-MOE Other Schools\\Other States",
                                      "MYS - stratum 07: Perlis non-“MOE Fully Residential Schools”",
                                      "MYS - stratum 08: Wilayah Persekutuan Putrajaya non-“MOE Fully Residential Schools”",
                                      "MYS - stratum 09: Wilayah Persekutuan Labuan non-“MOE Fully Residential Schools”"),
                            SCH.TYPE=c("Public",
                                       "Religious",
                                       "Technical",
                                       "SBP",
                                       "MARA",
                                       "Private",
                                       "Perlis Fully Residential",
                                       "Putrajaya Fully Residential",
                                       "Labuan Fully Residential"))

答案在于 setDT(通过引用将列表和 data.frames 强制转换为 data.table)。

使用我阅读here 的这行代码,它看起来有点长,但它解决了我的问题!老实说,在我理解下面最短的代码之前,我首先理解了这一点。

setDT(pisaMalaysia)[,SCH.TYPE := lookUpStratum$SCH.TYPE[match(pisaMalaysia$STRATUM,lookUpStratum$STRATUM)]]

几分钟后,我终于理解了这段代码 here 并生成了这段代码:

setDT(pisaMalaysia)[lookUpStratum,SCH.TYPE1 := i.SCH.TYPE, on = c(STRATUM = "STRATUM")]

我从同一帖子 here 中得到了这些答案。

检查一切是否相同:

table(pisaMalaysia$SCH.TYPE)
table(pisaMalaysia$SCH.TYPE1)
#' original data
pisaMalaysia[,table(STRATUM)]

结果:

> table(pisaMalaysia$SCH.TYPE)
   Labuan Fully Residential                        MARA    Perlis Fully Residential 
                         54                         122                          78 
                    Private                      Public Putrajaya Fully Residential 
                        385                        4929                          78 
                  Religious                         SBP                   Technical 
                        273                        2661                         281 

> table(pisaMalaysia$SCH.TYPE1)
   Labuan Fully Residential                        MARA    Perlis Fully Residential 
                         54                         122                          78 
                    Private                      Public Putrajaya Fully Residential 
                        385                        4929                          78 
                  Religious                         SBP                   Technical 
                        273                        2661                         281 

> pisaMalaysia[,table(STRATUM)]
STRATUM
                      MYS - stratum 01: MOE National Secondary School\\Other States 
                                                                               4929 
                               MYS - stratum 02: MOE Religious School\\Other States 
                                                                                273 
                               MYS - stratum 03: MOE Technical School\\Other States 
                                                                                281 
                                     MYS - stratum 04: MOE Fully Residential School 
                                                                               2661 
                MYS - stratum 05: non-MOE MARA Junior Science College\\Other States 
                                                                                122 
                              MYS - stratum 06: non-MOE Other Schools\\Other States 
                                                                                385 
                       MYS - stratum 07: Perlis non-“MOE Fully Residential Schools” 
                                                                                 78 
MYS - stratum 08: Wilayah Persekutuan Putrajaya non-“MOE Fully Residential Schools” 
                                                                                 78 
   MYS - stratum 09: Wilayah Persekutuan Labuan non-“MOE Fully Residential Schools” 
                                                                                 54 

谢谢!希望这对其他人也有帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-10
    • 1970-01-01
    • 1970-01-01
    • 2010-10-31
    相关资源
    最近更新 更多