{"action":"created","comment":{"url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/pulls/comments/226775262","pull_request_review_id":166687860,"id":226775262,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIyNjc3NTI2Mg==","diff_hunk":"@@ -1,261 +1,102 @@\n-\"\"\"\n-Wrapper which combines Formula (Terms) and an AbstractDataFrame\n-\n-This wrapper encapsulates all the information that's required to transform data\n-of the same structure as the wrapped data frame into a model matrix.  This goes\n-above and beyond what's expressed in the `Formula` itself, for instance\n-including information on how each categorical variable should be coded.\n-\n-Creating a `ModelFrame` first parses the `Formula` into `Terms`, checks which\n-variables are categorical and determines the appropriate contrasts to use, and\n-then creates the necessary contrasts matrices and stores the results.\n-\n-# Constructors\n-\n-```julia\n-ModelFrame(f::Formula, df::AbstractDataFrame; contrasts::Dict = Dict())\n-ModelFrame(ex::Expr, d::AbstractDataFrame; contrasts::Dict = Dict())\n-ModelFrame(terms::Terms, df::AbstractDataFrame; contrasts::Dict = Dict())\n-# Inner constructors:\n-ModelFrame(df::AbstractDataFrame, terms::Terms, nonmissing::BitArray)\n-ModelFrame(df::AbstractDataFrame, terms::Terms, nonmissing::BitArray, contrasts::Dict{Symbol, ContrastsMatrix})\n-```\n-\n-# Arguments\n-\n-* `f::Formula`: Formula whose left hand side is the *response* and right hand\n-  side are the *predictors*.\n-* `df::AbstractDataFrame`: The data being modeled.  This is used at this stage\n-  to determine which variables are categorical, and otherwise held for\n-  [`ModelMatrix`](@ref).\n-* `contrasts::Dict`: An optional Dict of contrast codings for each categorical\n-  variable.  Any unspecified variables will have [`DummyCoding`](@ref).  As a\n-  keyword argument, these can be either instances of a subtype of\n-  [`AbstractContrasts`](@ref), or a [`ContrastsMatrix`](@ref).  For the inner\n-  constructor, they must be [`ContrastsMatrix`](@ref)es.\n-* `ex::Expr`: An expression which will be converted into a `Formula`.\n-* `terms::Terms`: For inner constructor, the parsed `Terms` from the `Formula`.\n-* `nonmissing::BitArray`: For inner constructor, indicates the rows of `df` that\n-  contain no missing data.\n-\n-# Examples\n-\n-```julia\n-julia> df = DataFrame(x = 1:4, y = 5:8)\n-julia> mf = ModelFrame(@formula(y ~ 1 + x), df)\n-```\n-\n-\"\"\"\n-mutable struct ModelFrame\n-    df::AbstractDataFrame\n-    terms::Terms\n-    nonmissing::BitArray\n-    ## mapping from df keys to contrasts matrices\n-    contrasts::Dict{Symbol, ContrastsMatrix}\n+mutable struct ModelFrame{D,M}\n+    f::FormulaTerm\n+    schema\n+    data::D\n+    model::Type{M}\n end\n \n-is_categorical(::AbstractArray{<:Union{Missing, Real}}) = false\n-is_categorical(::AbstractArray) = true\n-\n-## Check for non-redundancy of columns.  For instance, if x is a factor with two\n-## levels, it should be expanded into two columns in y~0+x but only one column\n-## in y~1+x.  The default is the rank-reduced form (contrasts for n levels only\n-## produce n-1 columns).  In general, an evaluation term x within a term\n-## x&y&... needs to be \"promoted\" to full rank if y&... hasn't already been\n-## included (either explicitly in the Terms or implicitly by promoting another\n-## term like z in z&y&...).\n-##\n-## This modifies the Terms, setting `trms.is_non_redundant = true` for all non-\n-## redundant evaluation terms.\n-function check_non_redundancy!(trms::Terms, df::AbstractDataFrame)\n-\n-    (n_eterms, n_terms) = size(trms.factors)\n \n-    encountered_columns = Vector{eltype(trms.factors)}[]\n \n-    if trms.intercept\n-        push!(encountered_columns, zeros(eltype(trms.factors), n_eterms))\n+## copied from DataFrames:\n+function _nonmissing!(res, col)\n+    # workaround until JuliaLang/julia#21256 is fixed\n+    eltype(col) >: Missing || return\n+    \n+    @inbounds for (i, el) in enumerate(col)\n+        res[i] &= !ismissing(el)\n     end\n+end\n \n-    for i_term in 1:n_terms\n-        for i_eterm in 1:n_eterms\n-            ## only need to check eterms that are included and can be promoted\n-            ## (e.g., categorical variables that expand to multiple mm columns)\n-            if Bool(trms.factors[i_eterm, i_term]) && is_categorical(df[trms.eterms[i_eterm]])\n-                dropped = trms.factors[:,i_term]\n-                dropped[i_eterm] = 0\n-\n-                if dropped ∉ encountered_columns\n-                    trms.is_non_redundant[i_eterm, i_term] = true\n-                    push!(encountered_columns, dropped)\n-                end\n-\n-            end\n-        end\n-        ## once we've checked all the eterms in this term, add it to the list\n-        ## of encountered terms/columns\n-        push!(encountered_columns, view(trms.factors, :, i_term))\n+function _nonmissing!(res, col::CategoricalArray{>: Missing})\n+    for (i, el) in enumerate(col.refs)\n+        res[i] &= el > 0\n     end\n-\n-    return trms.is_non_redundant\n end\n \n-const DEFAULT_CONTRASTS = DummyCoding\n-\n-# get unique values, honoring levels order\n-_unique(x::AbstractCategoricalArray) = intersect(levels(x), unique(x))\n-_unique(x::AbstractCategoricalArray{T}) where {T>:Missing} =\n-    convert(Array{Missings.T(T)}, filter!(!ismissing, intersect(levels(x), unique(x))))\n+_select(d::ColumnTable, cols::NTuple{N,Symbol} where N) = NamedTuple{cols}(d)\n+_select(d::ColumnTable, cols::Vector{Symbol}) = _select(d, tuple(cols...))\n+_filter(d::T, rows) where T<:ColumnTable = T(([col[rows] for col in d]..., ))\n \n-function _unique(x::AbstractArray{T}) where T\n-    levs = T >: Missing ?\n-           convert(Array{Missings.T(T)}, filter!(!ismissing, unique(x))) :\n-           unique(x)\n-    try; sort!(levs); catch; end\n-    return levs\n-end\n-\n-## Set up contrasts:\n-## Combine actual DF columns and contrast types if necessary to compute the\n-## actual contrasts matrices, levels, and term names (using DummyCoding\n-## as the default)\n-function evalcontrasts(df::AbstractDataFrame, contrasts::Dict = Dict())\n-    evaledContrasts = Dict()\n-    for (term, col) in eachcol(df)\n-        is_categorical(col) || continue\n-        evaledContrasts[term] = ContrastsMatrix(haskey(contrasts, term) ?\n-                                                contrasts[term] :\n-                                                DEFAULT_CONTRASTS(),\n-                                                _unique(col))\n-    end\n-    return evaledContrasts\n-end\n+_size(d::ColumnTable) = (length(first(d)), length(d))\n+_size(d::ColumnTable, dim::Int) = _size(d)[dim]\n \n ## Default NULL handler.  Others can be added as keyword arguments\n-function missing_omit(df::DataFrame)\n-    cc = completecases(df)\n-    df[cc,:], cc\n+function missing_omit(d::T) where T<:ColumnTable\n+    nonmissings = trues(_size(d, 1))\n+    for col in d\n+        _nonmissing!(nonmissings, col)\n+    end\n+    map(disallowmissing, _filter(d, nonmissings)), nonmissings\n end\n \n-_droplevels!(x::Any) = x\n-_droplevels!(x::AbstractCategoricalArray) = droplevels!(x)\n-\n-function ModelFrame(trms::Terms, d::AbstractDataFrame;\n-                    contrasts::Dict = Dict())\n-    df, nonmissing = missing_omit(DataFrame(map(x -> d[x], trms.eterms), Symbol.(trms.eterms)))\n-    names!(df, Symbol.(string.(trms.eterms)))\n+missing_omit(data::T, formula::AbstractTerm) where T<:ColumnTable =\n+    missing_omit(_select(data, termvars(formula)))\n \n-    evaledContrasts = evalcontrasts(df, contrasts)\n+function ModelFrame(f::FormulaTerm, data::ColumnTable;\n+                    mod::Type{Mod}=StatisticalModel, contrasts=Dict{Symbol,Any}()) where Mod\n+    data, _ = missing_omit(data, f)\n \n-    ## Check for non-redundant terms, modifying terms in place\n-    check_non_redundancy!(trms, df)\n-\n-    ModelFrame(df, trms, nonmissing, evaledContrasts)\n+    sch = schema(f, data, contrasts)\n+    f = apply_schema(f, sch, Mod)\n+    \n+    ModelFrame(f, sch, data, mod)\n end\n \n-ModelFrame(df::AbstractDataFrame, term::Terms, nonmissing::BitArray) = ModelFrame(df, term, nonmissing, evalcontrasts(df))\n-ModelFrame(f::Formula, d::AbstractDataFrame; kwargs...) = ModelFrame(Terms(f), d; kwargs...)\n-ModelFrame(ex::Expr, d::AbstractDataFrame; kwargs...) = ModelFrame(Formula(ex), d; kwargs...)\n+ModelFrame(f::FormulaTerm, data; mod=StatisticalModel, contrasts=Dict{Symbol,Any}()) =\n+    ModelFrame(f, columntable(data); mod=mod, contrasts=contrasts)\n \n-\"\"\"\n-    setcontrasts!(mf::ModelFrame, new_contrasts::Dict)\n+model_matrix(mf::ModelFrame; data=mf.data) = model_cols(mf.f.rhs, data)\n+StatsBase.model_response(mf::ModelFrame; data=mf.data) = model_cols(mf.f.lhs, data)","path":"src/modelframe.jl","position":201,"original_position":201,"commit_id":"5cd6f0527518290c63c50b8073fda720c5527976","original_commit_id":"5cd6f0527518290c63c50b8073fda720c5527976","user":{"login":"kleinschmidt","id":135920,"node_id":"MDQ6VXNlcjEzNTkyMA==","avatar_url":"https://avatars0.githubusercontent.com/u/135920?v=4","gravatar_id":"","url":"https://api.github.com/users/kleinschmidt","html_url":"https://github.com/kleinschmidt","followers_url":"https://api.github.com/users/kleinschmidt/followers","following_url":"https://api.github.com/users/kleinschmidt/following{/other_user}","gists_url":"https://api.github.com/users/kleinschmidt/gists{/gist_id}","starred_url":"https://api.github.com/users/kleinschmidt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kleinschmidt/subscriptions","organizations_url":"https://api.github.com/users/kleinschmidt/orgs","repos_url":"https://api.github.com/users/kleinschmidt/repos","events_url":"https://api.github.com/users/kleinschmidt/events{/privacy}","received_events_url":"https://api.github.com/users/kleinschmidt/received_events","type":"User","site_admin":false},"body":"Yes, or during the `apply_schema` stage.  Although that might require putting the link/distribution as a type parameter on the GLM.  Then you could do\r\n\r\n```julia\r\napply_schema(f::FormulaTerm, schema, Mod::type{GLM{Link}}) where Link = \r\n    FormulaTerm(apply_schema(GLMResponse(f.lhs, Link), schema, Mod),\r\n               apply_schema(f.rhs, schema, Mod))\r\n```","created_at":"2018-10-19T20:39:03Z","updated_at":"2018-10-19T20:39:03Z","html_url":"https://github.com/JuliaStats/StatsModels.jl/pull/71#discussion_r226775262","pull_request_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/pulls/71","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/JuliaStats/StatsModels.jl/pulls/comments/226775262"},"html":{"href":"https://github.com/JuliaStats/StatsModels.jl/pull/71#discussion_r226775262"},"pull_request":{"href":"https://api.github.com/repos/JuliaStats/StatsModels.jl/pulls/71"}},"in_reply_to_id":226694278},"pull_request":{"url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/pulls/71","id":206832096,"node_id":"MDExOlB1bGxSZXF1ZXN0MjA2ODMyMDk2","html_url":"https://github.com/JuliaStats/StatsModels.jl/pull/71","diff_url":"https://github.com/JuliaStats/StatsModels.jl/pull/71.diff","patch_url":"https://github.com/JuliaStats/StatsModels.jl/pull/71.patch","issue_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/issues/71","number":71,"state":"open","locked":false,"title":"Terms 2.0: son of Terms","user":{"login":"kleinschmidt","id":135920,"node_id":"MDQ6VXNlcjEzNTkyMA==","avatar_url":"https://avatars0.githubusercontent.com/u/135920?v=4","gravatar_id":"","url":"https://api.github.com/users/kleinschmidt","html_url":"https://github.com/kleinschmidt","followers_url":"https://api.github.com/users/kleinschmidt/followers","following_url":"https://api.github.com/users/kleinschmidt/following{/other_user}","gists_url":"https://api.github.com/users/kleinschmidt/gists{/gist_id}","starred_url":"https://api.github.com/users/kleinschmidt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kleinschmidt/subscriptions","organizations_url":"https://api.github.com/users/kleinschmidt/orgs","repos_url":"https://api.github.com/users/kleinschmidt/repos","events_url":"https://api.github.com/users/kleinschmidt/events{/privacy}","received_events_url":"https://api.github.com/users/kleinschmidt/received_events","type":"User","site_admin":false},"body":"This is a pretty major re-thinking of how to represent terms in a formula.  It builds on #4, #54, and #57.  The basic idea is that the `@formula` macro lowers a formula expression to an expression where symbols are \"wrapped\" in a `Term` struct, and overloads operators like `+`, `&`, and `~` with methods of `Term`s that generate higher-order terms like interactions.  Additionally, this PR includes a mechanism by which calls to functions that don't have special meanings in the formula DSL are lowered to a call to `capture_call` which gets the original function called, the original expression, and an anonymous function that \"wraps\" that call.  The default result of that function is that it passes these onto a `FunctionTerm` constructor, but in principle package authors could intercept things at this point.  Whether or not a call is considered 'special' is also customizable, dispatching on `is_special(Val(::Symbol))`.\r\n\r\nThe other major new component is a schema representation that I \"borrowed\" from JuliaDB.ML.  Schemas are computed from a namedtuple of vectors (e.g., what DataStreams calls a Data.Table), and when applied to a formula will replace leaf `Term`s with `Categorical`/`ContinuousTerm`s.\r\n\r\nThe major _conceptual_ difference is that any subtype of `AbstractTerm` can generate model matrix columns, and the way that columns are combined to make higher order model matrices is handled by dispatch.  This provides, I think, much more flexibility in how package authors can \"plug into\" the formula pipeline, because they are no longer restricted to using fully-formed `ModelFrame`s.\r\n\r\nThat being said, I've tried to keep the ModelFrame/ModelMatrix structure for now to make it easier to see how things have changed.  I'd also like to consider how we actually use these structures to generate and fit models (e.g. #32).  But that's orthogonal enough that this is worth considering as is.\r\n\r\nThis is work in progress and I haven't even tried to get the tests passing yet because I wanted to talk about this at juliacon.  But I think it's close enough to the kind of structure I've had in mind for a long time that it's worth considering.","created_at":"2018-08-07T21:28:32Z","updated_at":"2018-10-19T20:39:03Z","closed_at":null,"merged_at":null,"merge_commit_sha":"060f6ec5ee317376a9b43ea780373231f1b3d5c3","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/pulls/71/commits","review_comments_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/pulls/71/comments","review_comment_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/pulls/comments{/number}","comments_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/issues/71/comments","statuses_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/statuses/5cd6f0527518290c63c50b8073fda720c5527976","head":{"label":"JuliaStats:dfk/terms2.0","ref":"dfk/terms2.0","sha":"5cd6f0527518290c63c50b8073fda720c5527976","user":{"login":"JuliaStats","id":2761531,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI3NjE1MzE=","avatar_url":"https://avatars2.githubusercontent.com/u/2761531?v=4","gravatar_id":"","url":"https://api.github.com/users/JuliaStats","html_url":"https://github.com/JuliaStats","followers_url":"https://api.github.com/users/JuliaStats/followers","following_url":"https://api.github.com/users/JuliaStats/following{/other_user}","gists_url":"https://api.github.com/users/JuliaStats/gists{/gist_id}","starred_url":"https://api.github.com/users/JuliaStats/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JuliaStats/subscriptions","organizations_url":"https://api.github.com/users/JuliaStats/orgs","repos_url":"https://api.github.com/users/JuliaStats/repos","events_url":"https://api.github.com/users/JuliaStats/events{/privacy}","received_events_url":"https://api.github.com/users/JuliaStats/received_events","type":"Organization","site_admin":false},"repo":{"id":70870657,"node_id":"MDEwOlJlcG9zaXRvcnk3MDg3MDY1Nw==","name":"StatsModels.jl","full_name":"JuliaStats/StatsModels.jl","private":false,"owner":{"login":"JuliaStats","id":2761531,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI3NjE1MzE=","avatar_url":"https://avatars2.githubusercontent.com/u/2761531?v=4","gravatar_id":"","url":"https://api.github.com/users/JuliaStats","html_url":"https://github.com/JuliaStats","followers_url":"https://api.github.com/users/JuliaStats/followers","following_url":"https://api.github.com/users/JuliaStats/following{/other_user}","gists_url":"https://api.github.com/users/JuliaStats/gists{/gist_id}","starred_url":"https://api.github.com/users/JuliaStats/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JuliaStats/subscriptions","organizations_url":"https://api.github.com/users/JuliaStats/orgs","repos_url":"https://api.github.com/users/JuliaStats/repos","events_url":"https://api.github.com/users/JuliaStats/events{/privacy}","received_events_url":"https://api.github.com/users/JuliaStats/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/JuliaStats/StatsModels.jl","description":"Specifying, fitting, and evaluating statistical models in Julia","fork":false,"url":"https://api.github.com/repos/JuliaStats/StatsModels.jl","forks_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/forks","keys_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/keys{/key_id}","collaborators_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/teams","hooks_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/hooks","issue_events_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/issues/events{/number}","events_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/events","assignees_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/assignees{/user}","branches_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/branches{/branch}","tags_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/tags","blobs_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/git/refs{/sha}","trees_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/git/trees{/sha}","statuses_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/statuses/{sha}","languages_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/languages","stargazers_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/stargazers","contributors_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/contributors","subscribers_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/subscribers","subscription_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/subscription","commits_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/commits{/sha}","git_commits_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/git/commits{/sha}","comments_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/comments{/number}","issue_comment_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/issues/comments{/number}","contents_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/contents/{+path}","compare_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/compare/{base}...{head}","merges_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/merges","archive_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/downloads","issues_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/issues{/number}","pulls_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/pulls{/number}","milestones_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/milestones{/number}","notifications_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/labels{/name}","releases_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/releases{/id}","deployments_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/deployments","created_at":"2016-10-14T03:28:16Z","updated_at":"2018-10-03T00:07:09Z","pushed_at":"2018-10-17T02:28:09Z","git_url":"git://github.com/JuliaStats/StatsModels.jl.git","ssh_url":"git@github.com:JuliaStats/StatsModels.jl.git","clone_url":"https://github.com/JuliaStats/StatsModels.jl.git","svn_url":"https://github.com/JuliaStats/StatsModels.jl","homepage":"","size":570,"stargazers_count":43,"watchers_count":43,"language":"Julia","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":12,"mirror_url":null,"archived":false,"open_issues_count":23,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":12,"open_issues":23,"watchers":43,"default_branch":"master"}},"base":{"label":"JuliaStats:master","ref":"master","sha":"c75823d7037f0ec68ed3b2e37c63ff9014851463","user":{"login":"JuliaStats","id":2761531,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI3NjE1MzE=","avatar_url":"https://avatars2.githubusercontent.com/u/2761531?v=4","gravatar_id":"","url":"https://api.github.com/users/JuliaStats","html_url":"https://github.com/JuliaStats","followers_url":"https://api.github.com/users/JuliaStats/followers","following_url":"https://api.github.com/users/JuliaStats/following{/other_user}","gists_url":"https://api.github.com/users/JuliaStats/gists{/gist_id}","starred_url":"https://api.github.com/users/JuliaStats/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JuliaStats/subscriptions","organizations_url":"https://api.github.com/users/JuliaStats/orgs","repos_url":"https://api.github.com/users/JuliaStats/repos","events_url":"https://api.github.com/users/JuliaStats/events{/privacy}","received_events_url":"https://api.github.com/users/JuliaStats/received_events","type":"Organization","site_admin":false},"repo":{"id":70870657,"node_id":"MDEwOlJlcG9zaXRvcnk3MDg3MDY1Nw==","name":"StatsModels.jl","full_name":"JuliaStats/StatsModels.jl","private":false,"owner":{"login":"JuliaStats","id":2761531,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI3NjE1MzE=","avatar_url":"https://avatars2.githubusercontent.com/u/2761531?v=4","gravatar_id":"","url":"https://api.github.com/users/JuliaStats","html_url":"https://github.com/JuliaStats","followers_url":"https://api.github.com/users/JuliaStats/followers","following_url":"https://api.github.com/users/JuliaStats/following{/other_user}","gists_url":"https://api.github.com/users/JuliaStats/gists{/gist_id}","starred_url":"https://api.github.com/users/JuliaStats/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JuliaStats/subscriptions","organizations_url":"https://api.github.com/users/JuliaStats/orgs","repos_url":"https://api.github.com/users/JuliaStats/repos","events_url":"https://api.github.com/users/JuliaStats/events{/privacy}","received_events_url":"https://api.github.com/users/JuliaStats/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/JuliaStats/StatsModels.jl","description":"Specifying, fitting, and evaluating statistical models in Julia","fork":false,"url":"https://api.github.com/repos/JuliaStats/StatsModels.jl","forks_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/forks","keys_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/keys{/key_id}","collaborators_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/teams","hooks_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/hooks","issue_events_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/issues/events{/number}","events_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/events","assignees_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/assignees{/user}","branches_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/branches{/branch}","tags_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/tags","blobs_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/git/refs{/sha}","trees_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/git/trees{/sha}","statuses_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/statuses/{sha}","languages_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/languages","stargazers_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/stargazers","contributors_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/contributors","subscribers_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/subscribers","subscription_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/subscription","commits_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/commits{/sha}","git_commits_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/git/commits{/sha}","comments_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/comments{/number}","issue_comment_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/issues/comments{/number}","contents_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/contents/{+path}","compare_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/compare/{base}...{head}","merges_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/merges","archive_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/downloads","issues_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/issues{/number}","pulls_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/pulls{/number}","milestones_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/milestones{/number}","notifications_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/labels{/name}","releases_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/releases{/id}","deployments_url":"https://api.github.com/repos/JuliaStats/StatsModels.jl/deployments","created_at":"2016-10-14T03:28:16Z","updated_at":"2018-10-03T00:07:09Z","pushed_at":"2018-10-17T02:28:09Z","git_url":"git://github.com/JuliaStats/StatsModels.jl.git","ssh_url":"git@github.com:JuliaStats/StatsModels.jl.git","clone_url":"https://github.com/JuliaStats/StatsModels.jl.git","svn_url":"https://github.com/JuliaStats/StatsModels.jl","homepage":"","size":570,"stargazers_count":43,"watchers_count":43,"language":"Julia","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":12,"mirror_url":null,"archived":false,"open_issues_count":23,"license":{"key":"other","name":"Other","spdx_id":"NOASSERTION","url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":12,"open_issues":23,"watchers":43,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/JuliaStats/StatsModels.jl/pulls/71"},"html":{"href":"https://github.com/JuliaStats/StatsModels.jl/pull/71"},"issue":{"href":"https://api.github.com/repos/JuliaStats/StatsModels.jl/issues/71"},"comments":{"href":"https://api.github.com/repos/JuliaStats/StatsModels.jl/issues/71/comments"},"review_comments":{"href":"https://api.github.com/repos/JuliaStats/StatsModels.jl/pulls/71/comments"},"review_comment":{"href":"https://api.github.com/repos/JuliaStats/StatsModels.jl/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/JuliaStats/StatsModels.jl/pulls/71/commits"},"statuses":{"href":"https://api.github.com/repos/JuliaStats/StatsModels.jl/statuses/5cd6f0527518290c63c50b8073fda720c5527976"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"kleinschmidt"}}