mlr-org / mlr3spatial Goto Github PK
View Code? Open in Web Editor NEWSpatial objects within the mlr3 ecosystem
Home Page: https://mlr3spatial.mlr-org.com
Spatial objects within the mlr3 ecosystem
Home Page: https://mlr3spatial.mlr-org.com
Many spatial predictions can become very large.
Doing the prediction in (parallel) chunks makes it possible to speed up the process a lot.
This is a generic problem though and can also be applied to non-spatial predictions.
Hence it should probably live in {mlr3}/{mlr3learners} directly.
Same as here: mlr-org/mlr3proba#301
Hello
I am trying to speed up the prediction of a random forest model and a SpatRaster using this package. However, I keep getting the same error message when creating the "backend" using the "DataBackendRaster" function. The error is:
Error: $ operator is invalid for atomic vectors
Here is a minimal example:
library("mlr3")
library("mlr3spatial")
# SpatRaster demo stack
stack_terra = demo_stack_spatraster(5)
# tasks
backend_terra = DataBackendRaster$new(stack_terra)
task_terra = as_task_regr(backend_terra, target = "x_1")
# Train learners
set.seed(42)
row_ids = sample(1:task_terra$nrow, 50)
learner_task_terra = lrn("regr.rpart")
learner_task_terra$parallel_predict = TRUE
learner_task_terra$train(task_terra, row_ids = row_ids)
# prediction
plan(multicore, workers = 4)
frank_parallel <- predict_spatial(task_terra, learner_task_terra, chunksize = 2000L)
Why doesn't this work?
Here my session:
R version 4.0.5 (2021-03-31)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows Server x64 (build 17763)Matrix products: default
locale:
[1] LC_COLLATE=German_Germany.1252 LC_CTYPE=German_Germany.1252 LC_MONETARY=German_Germany.1252 LC_NUMERIC=C LC_TIME=German_Germany.1252attached base packages:
[1] parallel grid stats graphics grDevices utils datasets methods baseother attached packages:
[1] mapmisc_1.8.0 terra_1.5-12 RColorBrewer_1.1-2 ecospat_3.2.1 gbm_2.1.8 ape_5.6-1 ade4_1.7-18 plyr_1.8.6
[9] openxlsx_4.2.5 data.table_1.14.2 foreach_1.5.1 rlist_0.4.6.2 stringr_1.4.0 latticeExtra_0.6-29 viridis_0.6.2 viridisLite_0.4.0
[17] rasterVis_0.51.1 lattice_0.20-41 rmaxent_0.8.5.9000 devtools_2.4.3 usethis_2.1.5 rJava_1.0-6 jsonlite_1.7.3 ENMeval_2.0.3
[25] magrittr_2.0.1 sf_1.0-5 rgeos_0.5-9 dismo_1.3-5 raster_3.5-11 sp_1.4-6 mlr3tuning_0.9.0 paradox_0.7.1
[33] mlr3spatial_0.1.0 mlr3_0.13.1loaded via a namespace (and not attached):
[1] SparseM_1.81 ModelMetrics_1.2.2.2 earth_5.3.1 nabor_0.5.0 tidyr_1.1.4 ggplot2_3.3.5 knitr_1.37
[8] multcomp_1.4-18 rpart_4.1-15 doParallel_1.0.16 generics_0.1.1 callr_3.7.0 TH.data_1.1-0 polspline_1.1.19
[15] proxy_0.4-26 future_1.23.0 ecodist_2.0.7 adehabitatMA_0.3.14 spatstat.data_2.1-2 xml2_1.3.3 lubridate_1.8.0
[22] adehabitatLT_0.3.25 assertthat_0.2.1 gower_0.2.2 xfun_0.29 adehabitatHR_0.4.19 fansi_1.0.2 DBI_1.1.2
[29] htmlwidgets_1.5.4 reshape_0.8.8 spatstat.geom_2.3-1 stats4_4.0.5 purrr_0.3.4 ellipsis_0.3.2 ks_1.13.3
[36] dplyr_1.0.7 ggpubr_0.4.0 backports_1.4.1 permute_0.9-5 deldir_1.0-6 vctrs_0.3.8 remotes_2.4.2
[43] quantreg_5.86 abind_1.4-5 caret_6.0-90 cachem_1.0.6 withr_2.4.3 checkmate_2.0.0 rgdal_1.5-28
[50] vegan_2.5-7 prettyunits_1.1.1 mclust_5.4.9 goftest_1.2-3 cluster_2.1.1 crayon_1.4.2 recipes_0.1.17
[57] pkgconfig_2.0.3 units_0.7-2 nlme_3.1-152 pkgload_1.2.4 nnet_7.3-15 rlang_0.4.12 globals_0.14.0
[64] lifecycle_1.0.1 MatrixModels_0.5-0 sandwich_3.0-1 palmerpenguins_0.1.0 PresenceAbsence_1.1.9 biomod2_3.5.1 randomForest_4.6-14
[71] rprojroot_2.0.2 polyclip_1.10-0 matrixStats_0.61.0 Matrix_1.3-2 carData_3.0-5 boot_1.3-28 zoo_1.8-9
[78] base64enc_0.1-3 processx_3.5.2 png_0.1-7 KernSmooth_2.23-18 pROC_1.18.0 classInt_0.4-3 maxnet_0.1.4
[85] maptools_1.1-2 parallelly_1.30.0 jpeg_0.1-9 rstatix_0.7.0 ggsignif_0.6.3 scales_1.1.1 memoise_2.0.1
[92] hexbin_1.28.2 compiler_4.0.5 plotrix_3.8-2 cli_3.1.0 listenv_0.8.0 ps_1.6.0 htmlTable_2.4.0
[99] Formula_1.2-4 MASS_7.3-53.1 mgcv_1.8-34 tidyselect_1.1.1 stringi_1.7.6 forcats_0.5.1 SDMtune_1.1.5
[106] spatstat.linnet_2.3-1 tools_4.0.5 mlr3misc_0.10.0 future.apply_1.8.1 CircStats_0.2-6 rstudioapi_0.13 uuid_1.0-3
[113] foreign_0.8-81 snowfall_1.84-6.1 gridExtra_2.3 prodlim_2019.11.13 ENMTools_1.0.5 digest_0.6.29 pracma_2.3.6
[120] lava_1.6.10 TeachingDemos_2.12 Rcpp_1.0.8 car_3.0-12 usdm_1.1-18 broom_0.7.11 httr_1.4.2
[127] mda_0.5-2 colorspace_2.0-2 rvest_1.0.2 fs_1.5.2 tensor_1.5 splines_4.0.5 lgr_0.4.3
[134] bbotk_0.4.0 conquer_1.2.1 spatstat.utils_2.3-0 sessioninfo_1.2.2 spatstat_2.3-0 timeDate_3043.102 poibin_1.5
[141] plotmo_3.6.1 testthat_3.1.1 ipred_0.9-12 R6_2.5.1 Hmisc_4.6-0 lhs_1.1.3 pillar_1.6.4
[148] htmltools_0.5.2 glue_1.6.0 fastmap_1.1.0 class_7.3-20 codetools_0.2-18 pkgbuild_1.3.1 mvtnorm_1.1-3
[155] utf8_1.2.2 spatstat.sparse_2.1-0 tibble_3.1.6 gtools_3.9.2 zip_2.2.0 survival_3.2-10 desc_1.4.0
[162] munsell_0.5.0 e1071_1.7-9 iterators_1.0.13 reshape2_1.4.4 gtable_0.3.0 spatstat.core_2.3-2 rms_6.2-0
In DataBackendRaster
there is this line
private$.data = terra::sources(assert_class(data, "SpatRaster"))$source
This breaks with the development version of terra
because terra::sources(data)
now returns a vector. It should work with both CRAN and the devel version if you change it to
private$.data = terra::sources(assert_class(data, "SpatRaster"), TRUE)$source
Can you please make that change?
When supplying a SpatRaster stack (very large one dim = 98939, 173775, 2), to predict_spatial(), it throws back an
error: [names<-] incorrect number of names
If you generate provisory stack via generate_stack(), it works just fine and also if you stack two radnom generated rasters. Appart from size, the only difference is having one source file, while stacking two selected files have two source links. I have tried to track down the error, and went all the way down to Task class, where it seems that as_data_backend returns an error.
Prepare for release:
git pull
devtools::build_readme()
urlchecker::url_check()
devtools::check(remote = TRUE, manual = TRUE)
devtools::check_win_devel()
rhub::check_for_cran()
revdepcheck::revdep_check(num_workers = 4)
cran-comments.md
git push
Submit to CRAN:
usethis::use_version('minor')
devtools::submit_cran()
Wait for CRAN...
git push
usethis::use_github_release()
usethis::use_dev_version()
git push
Hi, I'm not super sure of the status of this project but I've found something that might be useful for others doing similar processing. You are able to pass a trained learner onto terra
raster predictions. I'll include an example of classification and probability predictions below:
library(mlr3verse)
library(terra)
# Create raster dataset
r = rast(nrow = 500, ncol = 500)
x = init(r, fun="col")
r1 = rast(lapply(1:5, function(z) x + z))
names(r1) = paste0("lyr.", 1:nlyr(r1))
# Create point data
set.seed(1)
cn = round(runif(100, 1, ncell(r1)))
e = extract(r1, cn)
p = factor(sample(LETTERS, nrow(e), replace = TRUE))
v = data.frame(cbind(pa=p, e))
# Create task
task = TaskClassif$new(id = "data", backend = v, target = "pa")
levs = levels(task$truth())
# Create function to place predictions into raster data. In some cases, classes
# are dropped during probabiltiy calculations hence the inclusion of all 0 probs
# for those missing classes
pfmlr = function(model, ...) {
if(model$predict_type == "prob") {
p = model$predict_newdata(...)$data$prob
if(length(levs) != ncol(p)) {
missing = setdiff(levs, colnames(p))
pm = matrix(0, ncol = length(missing), nrow = nrow(p), dimnames = list(NULL, missing))
p = cbind(p, pm)
p = p[, levs]
}
p
} else {
model$predict_newdata(...)$data$response
}
}
model1 = lrn("classif.ranger", predict_type = "response")$train(task)
model2 = lrn("classif.ranger", predict_type = "prob")$train(task)
p1 = predict(r1, model1, fun = pfmlr, na.rm = TRUE)
p2 = predict(r1, model2, fun = pfmlr, na.rm = TRUE)
The output of this is a SpatRaster with either one layer for classification predictions, or multiple layers based on the number of classes for probability predictions. No doubt this could be modified to be a bit more universal, but as it stands currently this works well for a number of the classification model types. I just thought that I should place it somewhere in case someone else was scratching their head with raster predictions as well!
Hey everybody,
I am using R 4.1.0 on Ubuntu 20.04 LTS.
I was trying out your workflow from the tutorial:
https://mlr3spatial.mlr-org.com/articles/mlr3spatial.html
I already get stuck when defining the backend, using
backend = as_data_backend(stack)
gives me:
Error in methods::as(x, "SpatRaster") : no method or default for coercing βRasterBrickβ to βSpatRasterβ
I can read the tif from the stars package and the stack without problems. I get the same error with my own stars object read from a tif object.
Same happens with the stack_raster from the benchmark tutorial:
https://mlr3spatial.mlr-org.com/articles/benchmark.html
backend_raster = DataBackendRaster$new(stack_raster)
gives me:
Error in methods::as(x, "SpatRaster") : no method or default for coercing βRasterBrickβ to βSpatRasterβ
I had the latest version for mlr3 and mlr3spatial. I just updated stars from 0.5.3 to 0.5.5 and also got this message while installing (not an error though):
in method for βcoerceβ with signature β"stars","Raster"β: no definition for class βRasterβ
in method for βcoerceβ with signature β"stars_proxy","Raster"β: no definition for class βRasterβ
in method for βcoerceβ with signature β"stars","SpatRaster"β: no definition for class βSpatRasterβ
in** method for βcoerceβ with signature β"stars_proxy","SpatRaster"β: no definition for class βSpatRasterβ
in method for βcoerceβ with signature β"stars","Spatial"β: no definition for class βSpatialβ
in method for βcoerceβ with signature β"stars","STFDF"β: no definition for class βSTFDFβ
Re-installed both sf and stars, still same problem. Assigning the original stars object (stack
) to the class "Raster" or "SpatRaster" actually works. There seems to be an intermediate step where "stack" is conversed to a RasterBrick or falsely assumed to be a RasterBrick?
Doing it manually worked for me:
sr_stack = as(stack, "SpatRaster")
backend = DataBackendRaster$new(sr_stack)
Any ideas?
Thanks in advance,
Damon
And let users just pass the raster file directly?
Hi,
Can we have a gap filling approach within mlr3raster
?
mean
repeat last seen observation
Here are some examples of the problem and solutions for your reference:
LINK1
LINK2
LINK3
Best, Mo
To convert it into a factor for classification tasks, which requires the response to be a factor.
Prepare for release:
git pull
urlchecker::url_check()
devtools::build_readme()
devtools::check(remote = TRUE, manual = TRUE)
devtools::check_win_devel()
revdepcheck::revdep_check(num_workers = 4)
cran-comments.md
git push
Submit to CRAN:
usethis::use_version('minor')
devtools::submit_cran()
Wait for CRAN...
usethis::use_github_release()
usethis::use_dev_version(push = TRUE)
I just found this package and thought that I should plug the terra package. It's described as the replacement for the raster package and in my experience it's been a much quicker and smoother experience. I'm not sure of the lengths that you would need to go to in order to implement terra over raster, but I just wanted to include this since lots of work has already gone into writing a faster raster package.
In mlr3spatial::DataBackendRaster
you use
if (data[layer]@ptr$inMemory) {
That breaks with the development version of terra. The @ptr$ methods are really not safe for use in other packages. Can you use the "official" interface instead? In this case that could be:
inMemory(data[layer])
Thanks!
x
How do we want to handle predictions?
I'd favor (1) as this would play well with predict()
calls for different classes (terra, raster, stars).
cc @be-marc
In the example in ?predict_spatial
you use
terra::setCats(stack, layer = "y", value = value)
terra::setCats
was deprecated but I cannot remove it because of this reverse dependency. It would help me if you could replace it with
stack <- categories(stack, layer = "y", value = value)
There is also the more similar (identical, in fact)
set.cats(stack, layer = "y", value = value)
But I would suggest using categories
because it uses the standard R copy-on-modify semantics. The set.
methods such as set.cats
do not make a copy, meaning that if there is a copy of stack
in the workspace, it will also change. The set.
methods can be efficient inside a function when working on a new object, or if you know what you are doing, but I do not recommend it in examples like this.
Thanks!
Most converters will only work with other spatial objects as location information is needed.
as_rasterbrick_backend()
and as_terra_backend()
need cellsize information when coming from an sf
backendI.e. querying the CRS via terra::crs()
from a DataBackendRaster
returns nothing as we don't store the initial CRS info within the backend.
Visualization maybe via {mapview}.
Using a real-world example dataset might be better suited for demonstration purposes than an artificial raster.
@be-marc Currently the logger for mlr3spatial lives on the same level as the one for mlr3.
The recommended way for frameworks like mlr3 is actually to have it defined as a child-logger to mlr3.
mlr3pipelines already does so (and I've just added support in mlr3spatiotempcv)
> lgr::logger_tree()
root [info] -> 1 appender
ββmlr3
β ββmlr3pipelines
β ββmlr3spatiotempcv [warn]
ββmlr3spatial
See https://s-fleck.github.io/lgr/articles/lgr.html#hierarchy and https://github.com/mlr-org/mlr3pipelines/blob/5e2c8ee2f2516e9b70829cf8bfeb49a0023c7fa2/R/zzz.R#L26
This package depends on (depends, imports or suggests) raster and one or more of the retiring packages rgdal, rgeos or maptools (https://r-spatial.org/r/2022/04/12/evolution.html, https://r-spatial.org/r/2022/12/14/evolution2.html). Since raster 3.6.3
, all use of external FOSS library functionality has been transferred to terra, making the retiring packages very likely redundant. It would help greatly if you could remove dependencies on the retiring packages as soon as possible.
Any use of functions conditionally using raster without terra present. rgdal is not used in code and must be a relict from raster < 3.6
.
Not sure what it takes or if it's even possible for predict_spatial()
but we should at least evaluate if we can support progressr::with_progress()
for parallel prediction runs.
Hi,
R can't find demo_stack
to reproduce your example.
library(raster)
#> Loading required package: sp
library(mlr3)
#>
#> Attaching package: 'mlr3'
#> The following object is masked from 'package:raster':
#>
#> resample
library(mlr3raster)
library(data.table)
#>
#> Attaching package: 'data.table'
#> The following object is masked from 'package:raster':
#>
#> shift
stack = demo_stack(size = 1000000000, layers=5)
#> Error in demo_stack(size = 1e+09, layers = 5): could not find function "demo_stack"
writeRaster(stack, "demo_stack_500mb.tif")
#> Error in (function (classes, fdef, mtable) : unable to find an inherited method for function 'writeRaster' for signature '"standardGeneric", "character"'
rm(stack)
#> Warning in rm(stack): object 'stack' not found
Created on 2020-10-27 by the reprex package (v0.3.0)
devtools::session_info()
#> β Session info βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
#> setting value
#> version R version 4.0.3 (2020-10-10)
#> os Ubuntu 20.04.1 LTS
#> system x86_64, linux-gnu
#> ui X11
#> language (EN)
#> collate en_US.UTF-8
#> ctype en_US.UTF-8
#> tz Europe/Amsterdam
#> date 2020-10-27
#>
#> β Packages βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
#> package * version date lib source
#> assertthat 0.2.1 2019-03-21 [1] CRAN (R 4.0.2)
#> backports 1.1.10 2020-09-15 [1] CRAN (R 4.0.2)
#> callr 3.5.1 2020-10-13 [1] CRAN (R 4.0.3)
#> checkmate 2.0.0 2020-02-06 [1] CRAN (R 4.0.2)
#> cli 2.1.0 2020-10-12 [1] CRAN (R 4.0.3)
#> codetools 0.2-16 2018-12-24 [4] CRAN (R 4.0.0)
#> crayon 1.3.4 2017-09-16 [1] CRAN (R 4.0.2)
#> data.table * 1.13.2 2020-10-19 [1] CRAN (R 4.0.3)
#> desc 1.2.0 2018-05-01 [1] CRAN (R 4.0.2)
#> devtools 2.3.2 2020-09-18 [1] CRAN (R 4.0.2)
#> digest 0.6.27 2020-10-24 [1] CRAN (R 4.0.3)
#> ellipsis 0.3.1 2020-05-15 [1] CRAN (R 4.0.2)
#> evaluate 0.14 2019-05-28 [1] CRAN (R 4.0.2)
#> fansi 0.4.1 2020-01-08 [1] CRAN (R 4.0.2)
#> fs 1.5.0 2020-07-31 [1] CRAN (R 4.0.2)
#> glue 1.4.2 2020-08-27 [1] CRAN (R 4.0.2)
#> highr 0.8 2019-03-20 [1] CRAN (R 4.0.2)
#> htmltools 0.5.0 2020-06-16 [1] CRAN (R 4.0.2)
#> knitr 1.30 2020-09-22 [1] CRAN (R 4.0.2)
#> lattice 0.20-41 2020-04-02 [1] CRAN (R 4.0.2)
#> lgr 0.4.1 2020-10-20 [1] CRAN (R 4.0.3)
#> magrittr 1.5 2014-11-22 [1] CRAN (R 4.0.2)
#> memoise 1.1.0 2017-04-21 [1] CRAN (R 4.0.2)
#> mlr3 * 0.8.0 2020-10-21 [1] CRAN (R 4.0.3)
#> mlr3learners 0.4.1 2020-10-27 [1] Github (mlr-org/mlr3learners@0c68d7f)
#> mlr3misc 0.5.0 2020-08-13 [1] CRAN (R 4.0.2)
#> mlr3raster * 0.0.0.9000 2020-10-27 [1] Github (mlr-org/mlr3raster@c930d18)
#> paradox 0.5.0 2020-10-21 [1] CRAN (R 4.0.3)
#> pkgbuild 1.1.0 2020-07-13 [1] CRAN (R 4.0.2)
#> pkgload 1.1.0 2020-05-29 [3] CRAN (R 4.0.0)
#> prettyunits 1.1.1 2020-01-24 [1] CRAN (R 4.0.2)
#> processx 3.4.4 2020-09-03 [1] CRAN (R 4.0.2)
#> ps 1.4.0 2020-10-07 [1] CRAN (R 4.0.2)
#> R6 2.4.1 2019-11-12 [1] CRAN (R 4.0.2)
#> raster * 3.3-13 2020-07-17 [1] CRAN (R 4.0.2)
#> Rcpp 1.0.5 2020-07-06 [1] CRAN (R 4.0.2)
#> remotes 2.2.0 2020-07-21 [1] CRAN (R 4.0.2)
#> rlang 0.4.8 2020-10-08 [1] CRAN (R 4.0.3)
#> rmarkdown 2.5 2020-10-21 [1] CRAN (R 4.0.3)
#> rprojroot 1.3-2 2018-01-03 [1] CRAN (R 4.0.2)
#> sessioninfo 1.1.1 2018-11-05 [1] CRAN (R 4.0.2)
#> sp * 1.4-4 2020-10-07 [1] CRAN (R 4.0.3)
#> stringi 1.5.3 2020-09-09 [1] CRAN (R 4.0.2)
#> stringr 1.4.0 2019-02-10 [1] CRAN (R 4.0.2)
#> testthat 2.3.2 2020-03-02 [3] CRAN (R 4.0.0)
#> usethis 1.6.3 2020-09-17 [1] CRAN (R 4.0.2)
#> uuid 0.1-4 2020-02-26 [1] CRAN (R 4.0.2)
#> withr 2.3.0 2020-09-22 [1] CRAN (R 4.0.2)
#> xfun 0.18 2020-09-29 [1] CRAN (R 4.0.2)
#> yaml 2.2.1 2020-02-01 [1] CRAN (R 4.0.2)
#>
#> [1] /home/msheykhmousa/R/x86_64-pc-linux-gnu-library/4.0
#> [2] /usr/local/lib/R/site-library
#> [3] /usr/lib/R/site-library
#> [4] /usr/lib/R/library
terra
raster
sf
stars
The call never finishes due to the slowness and should actually finish in less than 10s.
The reason is that the single cell extraction is quite slow.
library("mlr3")
library("mlr3tuning")
library("mlr3spatial")
library("paradox")
logger = lgr::get_logger("bbotk")
logger$set_threshold("debug")
logger_mlr3 = lgr::get_logger("mlr3")
logger_mlr3$set_threshold("debug")
logger_mlr3tuning = lgr::get_logger("mlr3tuning")
logger_mlr3tuning$set_threshold("debug")
learner = lrn("classif.rpart")
tune_ps = ps(
cp = p_dbl(lower = 0.001, upper = 0.1),
minsplit = p_int(lower = 1, upper = 10)
)
terminator = trm("evals", n_evals = 2)
tuner = tnr("grid_search")
stack_classif = demo_stack_spatraster(1)
value = data.table::data.table(ID = c(0, 1), y = c("negative", "positive"))
terra::setCats(stack_classif, layer = "y", value = value)
backend_sp = as_data_backend(stack_classif)
task = as_task_classif(backend_sp, target = "y", positive = "positive")
hout = rsmp("holdout")
measure = msr("classif.ce")
instance = TuningInstanceSingleCrit$new(
task = task,
learner = learner,
resampling = hout,
measure = measure,
search_space = tune_ps,
terminator = terminator
)
instance
tuner$optimize(instance)
How do we want to store spatial objects from {terra}, {raster}, {stars}.
cc @be-marc
Prepare for release:
git pull
devtools::build_readme()
urlchecker::url_check()
devtools::check(remote = TRUE, manual = TRUE)
devtools::check_win_devel()
rhub::check_for_cran()
revdepcheck::revdep_check(num_workers = 4)
cran-comments.md
git push
Submit to CRAN:
usethis::use_version('patch')
devtools::submit_cran()
Wait for CRAN...
git push
usethis::use_github_release()
usethis::use_dev_version()
git push
Is it possible to plot probabilities instead of responses for classif tasks using predict_spatial
?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.