備忘ログ

チラシの裏的備忘録&メモ

CRANリポジトリからパッケージが多くremoveされる日を調べてみた

RのパッケージはしばしばCRANリポジトリからremoveされArchivesとなる(CRANのArchivesには、removeされたパッケージだけではなくパッケージがアップデートされた時に以前のパッケージもある)。

CRANリポジトリからremoveされるのは、多くの場合はCRANが定期的に行っているパッケージのR CMD checkの結果ERRORとなり、更新がなされない場合にCRANからremoveされArchiveとなる。特にR本体のマイナーバージョン以上のアップデートでしばしば起こるとのことで、コードそのものよりもRのPolicyや細かい挙動の変更に伴って弾かれてしまっている例があると考えている。

ところでどういうタイミングでパッケージがremoveされているのかというのが気になった。パッケージがremoveされることが多い日があるのか、など見てみたいと思った。

CRANリポジトリftpサーバでも提供されており、

ここの中身をみるとArchivesとなっているパッケージのリストや、更新日がわかる。現在CRANリポジトリで利用できないパッケージのArchivesの更新日はCRANリポジトリからパッケージがremoveされた日になっている。この情報と、現在利用可能なパッケージのリストをつきあわせると、CRANリポジトリからremoveされたパッケージのリストを抽出できる。

ということでまずは使うデータセットを作っていく。

# {tiryvese}をいろいろ使って読み込んでおく(全部は使わない)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.4.4     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
# Archivesにあるパッケージのリストのデータセットを作る
pkg_arc <- read.table(curl::curl("ftp://cran.r-project.org/pub/R/src/contrib/Archive/"), stringsAsFactors = FALSE)
pkg_arc <- pkg_arc |> 
  # 236はパッケージではないREDEMEディレクトリ
  filter(V5 != 236) |>
  select(Package = V9, M = V6, D = V7, Y = V8) |>
  mutate(Y = case_when(!str_detect(Y, ":") ~ as.numeric(Y),
                       M %in% month.abb[1:month(Sys.Date())] ~ year(Sys.Date()),
                       .default = year(Sys.Date()) - 1)) |> 
  mutate(Date = as_date(mapply(paste0, Y, M, D)))
## Warning: There was 1 warning in `mutate()`.
## ℹ In argument: `Y = case_when(...)`.
## Caused by warning:
## !  強制変換により NA が生成されました
# 現在CRANで利用可能なすべてのパッケージのリストのデータセットを作る
# available.package()は現在の環境(RバージョンとOS)で利用可能なものとなるのですべてのパッケージではない
pkg_db <- tools::CRAN_package_db()

ところで、{tools}CRAN_package_db()では一部パッケージ(名)の重複がある。具体的には次のパッケージ(名)が重複して抽出されている。

pkg_db$Package[duplicated(pkg_db$Package)]
##  [1] "boot"       "class"      "cluster"    "codetools"  "foreign"   
##  [6] "KernSmooth" "lattice"    "MASS"       "Matrix"     "mgcv"      
## [11] "nlme"       "nnet"       "rpart"      "spatial"    "survival"

重複しているものはひとつを除外すればいい(最初に出てくる方だけ残す)。

pkg_db <- pkg_db[!duplicated(pkg_db$Package), ]

Archivesにあるパッケージ数、現在CRANから利用可能なパッケージ数、archivesにのみあるパッケージ(つまりCRANからremoveされたパッケージ)を数、現在利用可能なパッケージでarchivesにないパッケージ(初版のみのパッケージ)数を確認してみる。

# archivesにあるパッケージ数
n_arc <- length(pkg_arc$Package)
n_arc
## [1] 22408
# 現在利用可能なパッケージ数
n_db <- length(pkg_db$Package)
n_db
## [1] 20443
# archivesにのみあるパッケージ(CRANからremoveされたパッケージ)数
n_only_arc <- length(pkg_arc$Package[! pkg_arc$Package %in% pkg_db$Package])
n_only_arc
## [1] 6326
# 現在利用可能なパッケージでarchivesにないパッケージ(初版のみのパッケージ)数
n_only_db <- length(pkg_db$Package[! pkg_db$Package %in% pkg_arc$Package])
n_only_db
## [1] 4361

ところで、removeされた後にCRANに再登録されたパッケージ等はここではCRANで利用可能なパッケージとしてカウントされている。6326ものパッケージがCRANからremoveされていることがわかる。

一応検算しておく。

# 検算
# 現在利用可能なパッケージ数 = archivesにあるパッケージ数 - archivesにのみあるパッケージ数 + まだarchivesされていないパッケージ数
n_db
## [1] 20443
n_arc - n_only_arc + n_only_db
## [1] 20443

ここからいつパッケージがremoveされたのかをみていく。CRANからremoveされたパッケージだけのデータセットを作る。

# removeされたパッケージだけのデータセットを作る
pkg_remove <- pkg_arc[! pkg_arc$Package %in% pkg_db$Package, ]

年ごとにどのくらいパッケージがremoveされているかを見てみる。

# 年ごと
pkg_remove_year <- pkg_remove |> 
  summarise(n = n(), .by = Y) |> 
  complete(Y = full_seq(Y, 1)) |> 
  replace_na(list(n = 0))
# 年ごと可視化
ggplot(data = pkg_remove_year, aes(x = Y, y = n)) +
  geom_line()

2022年に最も多くのパッケージがremoveされていることがわかる。

日付ごとに見てみる。

# 日付ごと
pkg_remove_day <- pkg_remove |> 
  summarise(n = n(), .by = Date) |> 
  complete(Date = full_seq(Date, 1)) |> 
  replace_na(list(n = 0))
# 日ごと可視化
ggplot(data = pkg_remove_day, aes(x = `Date`, y = n)) +
  geom_line()

コンスタントにremoveされているのではなくある程度波がある様子。おそらく、CRAN Policyの変更、R CMD checkで使われるライブラリやRのバージョンの変更のタイミングなどに合わせてremoveの嵐が吹き荒れるのかと思う。ただ、これらがいつ変更になったのかのログを見つけることができなかったのでこれらが一致しているのかは精査はできていない。

CRANからremoveされたパッケージ数が多い日トップ10をみてみる。head(11)としているのはArchivesの日付の最も古い日付けが2008年2月16日となっており、この日にまとめられているだけではないかと思うのでトップ10からは除外されるべきと思う。

# removeされたパッケージの多い日トップ10
arrange(pkg_remove_day, -n) |> 
  head(11)
## # A tibble: 11 × 2
##    Date           n
##    <date>     <int>
##  1 2022-05-09   204
##  2 2022-06-20   162
##  3 2023-08-18   115
##  4 2008-02-16    84
##  5 2020-02-19    65
##  6 2023-10-16    64
##  7 2022-04-27    61
##  8 2022-06-10    61
##  9 2023-08-19    54
## 10 2018-06-17    51
## 11 2022-06-13    47

となっている。1日に200以上のパッケージがremoveされるなんて結構な大嵐だと思う。15年以上の歴史でこの2022年5月9日だけでremoveされArchivesのみとなったパッケージ全体の3.2%がremoveされている。

ちなみに、removeされたパッケージとして2008年2月16日にArchivesに登録されたパッケージは次の通り。

pkg_arc$Package[pkg_arc$Date == min(pkg_arc$Date)]
##  [1] "AnalyzeIO"     "CoCoAn"        "DBI.RODBC"     "DBI.RPgSQL"   
##  [5] "Dopt"          "FLCore"        "FLEDA"         "FortranCallsR"
##  [9] "GLMMGibbs"     "GammaTest"     "GeneSOM"       "HTML"         
## [13] "InfNet"        "Java"          "Malmig"        "RGtk2.10"     
## [17] "RPgSQL"        "Rcmdr.HH"      "Rdbi"          "Rdbi.PgSQL"   
## [21] "RmSQL"         "Rnotes"        "Rstreams"      "SAGx"         
## [25] "bats"          "baymvb"        "climate.plot"  "colSums"      
## [29] "ctest"         "cxx"           "dseplus"       "ensemble"     
## [33] "event.chart"   "exactDistr"    "funfits"       "gRcox"        
## [37] "grasper"       "grid"          "haplo.score"   "hpower"       
## [41] "integrate"     "limma"         "lme"           "mclust1998"   
## [45] "meanscore"     "micEcdat"      "mscalib"       "msgcop"       
## [49] "multilm"       "multiv"        "netCDF"        "newallelic"   
## [53] "nlrq"          "nls"           "normix"        "npConfRatio"  
## [57] "nprq"          "phyloarray"    "pls.pcr"       "polymars"     
## [61] "ppr"           "ptproc"        "ratetables"    "rcompletion"  
## [65] "regexp"        "roblm"         "runStat"       "seao"         
## [69] "seao.gui"      "serialize"     "splines"       "spsarlm"      
## [73] "sptests"       "spweights"     "stataread"     "survival4"    
## [77] "survival5"     "syskern"       "tapiR"         "tcltk"        
## [81] "timeslab"      "twostage"      "vtcl"          "write.snns"   
## [85] "zmatrix"

一番パッケージがremoveされた2022-05-09は次の通り。

# 一番多い日にremoveされたパッケージ
pkg_arc$Package[pkg_arc$Date == head(arrange(pkg_remove_day, -n), 1)$Date]
##   [1] "AMAP.Seq"                    "AMOEBA"                     
##   [3] "ASPBay"                      "AllPossibleSpellings"       
##   [5] "BAEssd"                      "BCellMA"                    
##   [7] "BayHaz"                      "BaySIC"                     
##   [9] "CARS"                        "CISE"                       
##  [11] "CNOGpro"                     "COBRA"                      
##  [13] "CRAC"                        "CVTuningCov"                
##  [15] "CityPlot"                    "ConNEcT"                    
##  [17] "DBGSA"                       "DCGL"                       
##  [19] "DIME"                        "DSviaDRM"                   
##  [21] "Demerelate"                  "DescToolsAddIns"            
##  [23] "DunnettTests"                "EBASS"                      
##  [25] "ES"                          "FAMT"                       
##  [27] "FBN"                         "FactMixtAnalysis"           
##  [29] "Familias"                    "FitAR"                      
##  [31] "FlickrAPI"                   "GESTr"                      
##  [33] "GExMap"                      "GWG"                        
##  [35] "GeneF"                       "GeoDE"                      
##  [37] "HAPim"                       "HDMD"                       
##  [39] "HIest"                       "HarmonicRegression"         
##  [41] "HiLMM"                       "HyPhy"                      
##  [43] "IBDhaploRtools"              "ICE"                        
##  [45] "InfDim"                      "InteractiveIGraph"          
##  [47] "KANT"                        "LEAPFrOG"                   
##  [49] "Lambda4"                     "LocFDRPois"                 
##  [51] "MATTOOLS"                    "MC2toPath"                  
##  [53] "MConjoint"                   "MImix"                      
##  [55] "MInt"                        "Methplot"                   
##  [57] "MiST"                        "MuFiCokriging"              
##  [59] "NPHMC"                       "OOmisc"                     
##  [61] "PAGI"                        "PharmPow"                   
##  [63] "PlotRegionHighlighter"       "PriorCD"                    
##  [65] "R2DGC"                       "RAD"                        
##  [67] "RBitmoji"                    "REQS"                       
##  [69] "RIFS"                        "RSwissMaps"                 
##  [71] "RWebLogo"                    "RelValAnalysis"             
##  [73] "Rothermel"                   "Runiversal"                 
##  [75] "SEMrushR"                    "SQDA"                       
##  [77] "SUE"                         "ShinyImage"                 
##  [79] "SocialNetworks"              "SolveRationalMatrixEquation"
##  [81] "SpatialBall"                 "SportsAnalytics"            
##  [83] "TERAplusB"                   "TiddlyWikiR"                
##  [85] "UBCRM"                       "UScensus2000cdp"            
##  [87] "VBTree"                      "VIF"                        
##  [89] "VarBundle"                   "VarSwapPrice"               
##  [91] "Voss"                        "YaleToolkit"                
##  [93] "YieldCurve"                  "ZipRadius"                  
##  [95] "aGE"                         "akmeans"                    
##  [97] "asVPC"                       "audiolyzR"                  
##  [99] "barcode"                     "bbo"                        
## [101] "beadarrayFilter"             "benchden"                   
## [103] "betaBayes"                   "bolasso"                    
## [105] "bootspecdens"                "bvenn"                      
## [107] "cartools"                    "catspec"                    
## [109] "ccChooser"                   "cheb"                       
## [111] "citbcmst"                    "citccmst"                   
## [113] "ciuupi"                      "cleanerR"                   
## [115] "clinPK"                      "clusterGenomics"            
## [117] "coexist"                     "collectArgs"                
## [119] "compareODM"                  "coreTDT"                    
## [121] "cosmoFns"                    "countyfloods"               
## [123] "crn"                         "crrp"                       
## [125] "customsteps"                 "cytoDiv"                    
## [127] "datadigest"                  "deseasonalize"              
## [129] "dfexplore"                   "dielectric"                 
## [131] "displayHTS"                  "documair"                   
## [133] "dotdot"                      "dragracer"                  
## [135] "dupiR"                       "edcc"                       
## [137] "emme2"                       "epade"                      
## [139] "errorizer"                   "expose"                     
## [141] "exsic"                       "extfunnel"                  
## [143] "eyetracking"                 "fakeR"                      
## [145] "fam2r"                       "fcd"                        
## [147] "forward"                     "fts"                        
## [149] "gRapfa"                      "gendata"                    
## [151] "geneListPie"                 "genotypeR"                  
## [153] "glmdm"                       "hbm"                        
## [155] "hiPOD"                       "highD2pop"                  
## [157] "hornpa"                      "hqmisc"                     
## [159] "hsicCCA"                     "hsmm"                       
## [161] "imputeMDR"                   "infra"                      
## [163] "infutil"                     "interferenceCI"             
## [165] "intubate"                    "jointPm"                    
## [167] "knnIndep"                    "labelrank"                  
## [169] "loop"                        "lpme"                       
## [171] "lsa"                         "majesticR"                  
## [173] "marl"                        "mazeinda"                   
## [175] "mcll"                        "metaplotr"                  
## [177] "mgpd"                        "miRada"                     
## [179] "minxent"                     "mmm2"                       
## [181] "modiscloud"                  "msda"                       
## [183] "muma"                        "mut"                        
## [185] "myepisodes"                  "mztwinreg"                  
## [187] "ncg"                         "networksis"                 
## [189] "nlmeODE"                     "notifyR"                    
## [191] "optAUC"                      "orderbook"                  
## [193] "p2distance"                  "pacbpred"                   
## [195] "paleoMAS"                    "parboost"                   
## [197] "parcoords"                   "pathlibr"                   
## [199] "pcmabc"                      "phenability"                
## [201] "phyloland"                   "planar"                     
## [203] "plpoisson"                   "plsr"                       
## [205] "pmcgd"                       "pnmtrem"                    
## [207] "popKorn"                     "probFDA"                    
## [209] "probemod"                    "proteomicdesign"            
## [211] "pvsR"                        "qLearn"                     
## [213] "r511"                        "rateratio.test"             
## [215] "rcane"                       "relMix"                     
## [217] "reweight"                    "rfigshare"                  
## [219] "rgabriel"                    "ri"                         
## [221] "rpcdsearch"                  "rsurfer"                    
## [223] "rvTDT"                       "sBF"                        
## [225] "scar"                        "scenario"                   
## [227] "semdiag"                     "sensitivityPStrat"          
## [229] "sigmaNet"                    "skda"                       
## [231] "smcure"                      "snpStatsWriter"             
## [233] "spatialnbda"                 "sprsmdl"                    
## [235] "ssh.utils"                   "ssvd"                       
## [237] "subtype"                     "svSocket"                   
## [239] "symbols"                     "tiger"                      
## [241] "tmle.npvi"                   "truncgof"                   
## [243] "vrmlgen"                     "weco"                       
## [245] "wmlf"                        "xtune"