\[Self \: Sufficiency \: Ratio = \frac{Earned \: Income}{Total \: Expenses} \]
The Self Sufficiency Ratio measures the proportion of operating expenses that are covered by earned income.
This metric is a good measure of how long an organization can survive without grants. Higher values mean it is more self-sufficient, meaning it could cover its costs longer without collecting any grants, rents, royalties, or sales of inventory. This ratio is primarily useful for organizations that have earned revenue through developers’ fees, management fees, memberships, or tuition. Higher values mean organizations have more autonomy and flexibility. They generally improve over time as an organization grows. In the early stages, these ratios tend to be lower but the goal is to make them as high as possible.
Note: This data is available for both 990EZ and full 990 filers.
Numerator: Program service revenue, EOY
* Denominator: Total Expenses, EOY
# TEMPORARY VARIABLES
<- core$totprgmrevnue
earned_income <- core$totfuncexpns
total_expenses
# can't divide by zero
== 0 ] <- NA
total_expenses[ total_expenses
# SAVE RESULTS
$selfsufficiency <- ( earned_income / total_expenses )
core# summary( core$selfsufficiency )
.05 <- quantile( core$selfsufficiency, 0.05, na.rm=T )
x.95 <- quantile( core$selfsufficiency, 0.95, na.rm=T )
x
ggplot( core, aes(x = selfsufficiency ) ) +
geom_density( alpha = 0.5) +
xlim( x.05, x.95 )
Winsorization: All extreme values have been capped by replacing any values below the 5% distribution and above the 95% distribution with the 5% and 95% values. Consequently the end tails to all density charts may be slightly higher than reality but the visuals will be scaled for better viewing (not skewed by outliers).
.05 <- quantile( core$selfsufficiency, 0.05, na.rm=T )
x.95 <- quantile( core$selfsufficiency, 0.95, na.rm=T )
x
<- core
core2
# proportion of values that are negative
# mean( core$selfsufficiency < 0, na.rm=T )
# proption of values above 1%
# mean( core$selfsufficiency > 5, na.rm=T )
# WINSORIZATION AT 5th and 95th PERCENTILES
$selfsufficiency[ core2$selfsufficiency < x.05 ] <- x.05
core2$selfsufficiency[ core2$selfsufficiency > x.95 ] <- x.95 core2
Tax data is available for full 990 filers, so this metric does not describe any organizations with Gross receipts < $200,000 and Total assets < $500,000. Some organizations with receipts or assets below those thresholds may have filed a full 990, but these would be exceptions.
Convert all monetary variables to thousands of dollars.
%>%
core2 mutate( selfsufficiency = selfsufficiency * 100,
totrevenue = totrevenue / 1000,
totfuncexpns = totfuncexpns / 1000,
lndbldgsequipend = lndbldgsequipend / 1000,
totassetsend = totassetsend / 1000,
totliabend = totliabend / 1000,
totnetassetend = totnetassetend / 1000 ) %>%
select( STATE, NTEE1, NTMAJ12,
selfsufficiency,
AGE,
totrevenue, totfuncexpns,
lndbldgsequipend, totassetsend, %>%
totnetassetend, totliabend )
stargazer( type = s.type,
digits=0,
summary.stat = c("min","p25","median",
"mean","p75","max", "sd"),
covariate.labels = c("Self Sufficiency Ratio*", "Age",
"Revenue ($1k)", "Expenses($1k)",
"Buildings ($1k)", "Total Assets ($1k)",
"Net Assets ($1k)", "Liabiliies ($1k)"))
Statistic | Min | Pctl(25) | Median | Mean | Pctl(75) | Max | St. Dev. |
Self Sufficiency Ratio* | 0 | 3 | 29 | 40 | 72 | 114 | 38 |
Age | 3 | 22 | 30 | 32 | 41 | 95 | 15 |
Revenue (1k) | -5,377 | 259 | 909 | 4,522 | 3,672 | 408,932 | 14,286 |
Expenses(1k) | 0 | 263 | 840 | 4,192 | 3,328 | 382,667 | 13,466 |
Buildings (1k) | -4 | 79 | 824 | 3,504 | 2,868 | 513,509 | 13,210 |
Total Assets (1k) | -7,552 | 778 | 2,446 | 9,262 | 7,477 | 672,021 | 27,039 |
Net Assets (1k) | -178,870 | 156 | 1,094 | 4,553 | 4,079 | 531,068 | 15,470 |
Liabiliies (1k) | -2,707 | 115 | 816 | 4,709 | 3,133 | 705,623 | 18,722 |
What proportion of orgs have Self Sufficiency Ratios equal to
zero (no income)?
<- mean( core2$selfsufficiency == 0, na.rm=T ) prop.zero
In the sample, 18 percent of the organizations have Self Sufficiency ratios equal to zero, meaning they have no earned income. These organizations are dropped from subsequent graphs to keep the visualizations clean. The interpretation of the graphics should be the distributions of Self Sufficiency ratios for organizations that are earning at least $1 of income.
###
### ADD QUANTILES
###
### function create_quantiles() defined in r-functions.R
$exp.q <- create_quantiles( var=core2$totfuncexpns, n.groups=5 )
core2$rev.q <- create_quantiles( var=core2$totrevenue, n.groups=5 )
core2$asset.q <- create_quantiles( var=core2$totnetassetend, n.groups=5 )
core2$age.q <- create_quantiles( var=core2$AGE, n.groups=5 )
core2$land.q <- create_quantiles( var=core2$lndbldgsequipend, n.groups=5 ) core2
<- min( core$selfsufficiency, na.rm=T )
min.x <- max( core$selfsufficiency, na.rm=T )
max.x
ggplot( core2, aes(x = selfsufficiency )) +
geom_density( alpha = 0.5 ) +
xlim( min.x, max.x ) +
xlab( variable.label ) +
theme( axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank() )
<- core2 %>% filter( ! is.na(NTEE1) )
core3 table( core3$NTEE1) %>% sort(decreasing=TRUE) %>% kable()
Var1 | Freq |
---|---|
Housing | 2837 |
Community Development | 1585 |
Human Services | 1102 |
<- table( factor(core3$NTEE1) )
t <- data.frame( x=Inf, y=Inf,
df N=paste0( "N=", as.character(t) ),
NTEE1=names(t) )
ggplot( core3, aes( x=selfsufficiency ) ) +
geom_density( alpha = 0.5) +
# xlim( -0.1, 1 ) +
labs( title="Nonprofit Subsectors" ) +
xlab( variable.label ) +
facet_wrap( ~ NTEE1, nrow=1 ) +
theme_minimal( base_size = 15 ) +
theme( axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank(),
strip.text = element_text( face="bold") ) + # size=20
geom_text( data=df,
aes(x, y, label=N ),
hjust=2, vjust=3,
color="gray60", size=6 )
table( core2$Region) %>% kable()
Var1 | Freq |
---|---|
Midwest | 1444 |
Northeast | 1368 |
South | 1610 |
West | 1088 |
<- table( factor(core2$Region) )
t <- data.frame( x=Inf, y=Inf,
df N=paste0( "N=", as.character(t) ),
Region=names(t) )
%>%
core2 filter( ! is.na(Region) ) %>%
ggplot( aes(selfsufficiency) ) +
geom_density( alpha = 0.5 ) +
xlab( "Census Regions" ) +
ylab( variable.label ) +
facet_wrap( ~ Region, nrow=3 ) +
theme_minimal( base_size = 22 ) +
theme( axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank() ) +
geom_text( data=df,
aes(x, y, label=N ),
hjust=2, vjust=3,
color="gray60", size=6 )
table( core2$Division ) %>% kable()
Var1 | Freq |
---|---|
East North Central | 1038 |
East South Central | 289 |
Middle Atlantic | 904 |
Mountain | 303 |
New England | 464 |
Pacific | 785 |
South Atlantic | 900 |
West North Central | 406 |
West South Central | 421 |
<- table( factor(core2$Division) )
t <- data.frame( x=Inf, y=Inf,
df N=paste0( "N=", as.character(t) ),
Division=names(t) )
%>%
core2 filter( ! is.na(Division) ) %>%
ggplot( aes(selfsufficiency) ) +
geom_density( alpha = 0.5 ) +
xlab( "Census Sub-Regions (10)" ) +
ylab( variable.label ) +
facet_wrap( ~ Division, nrow=3 ) +
theme_minimal( base_size = 22 ) +
theme( axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank() ) +
geom_text( data=df,
aes(x, y, label=N ),
hjust=2, vjust=3,
color="gray60", size=6 )
ggplot( core2, aes(x = totfuncexpns )) +
geom_density( alpha = 0.5 ) +
xlim( quantile(core2$totfuncexpns, c(0.02,0.98), na.rm=T ) )
$totfuncexpns[ core2$totfuncexpns < 1 ] <- 1
core2# core2$totfuncexpns[ is.na(core2$totfuncexpns) ] <- 1
if( nrow(core2) > 10000 )
{<- sample_n( core2, 10000 )
core3 else
}
{<- core2
core3
}
jplot( log10(core3$totfuncexpns), core3$selfsufficiency,
xlab="Nonprofit Size (logged Expenses)",
ylab=variable.label,
xaxt="n", xlim=c(3,10) )
axis( side=1,
at=c(3,4,5,6,7,8,9,10),
labels=c("1k","10k","100k","1m","10m","100m","1b","10b") )
%>%
core2 filter( ! is.na(exp.q) ) %>%
ggplot( aes(selfsufficiency) ) +
geom_density( alpha = 0.5) +
labs( title="Nonprofit Size (logged expenses)" ) +
xlab( variable.label ) +
facet_wrap( ~ exp.q, nrow=3 ) +
theme_minimal( base_size = 22 ) +
theme( axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank() )
ggplot( core2, aes(x = totrevenue )) +
geom_density( alpha = 0.5 ) +
xlim( quantile(core2$totrevenue, c(0.02,0.98), na.rm=T ) ) +
theme( axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank() )
$totrevenue[ core2$totrevenue < 1 ] <- 1
core2
if( nrow(core2) > 10000 )
{<- sample_n( core2, 10000 )
core3 else
}
{<- core2
core3
}
jplot( log10(core3$totrevenue), core3$selfsufficiency,
xlab="Nonprofit Size (logged Revenue)",
ylab=variable.label,
xaxt="n", xlim=c(3,10) )
axis( side=1,
at=c(3,4,5,6,7,8,9,10),
labels=c("1k","10k","100k","1m","10m","100m","1b","10b") )
%>%
core2 filter( ! is.na(rev.q) ) %>%
ggplot( aes(selfsufficiency) ) +
geom_density( alpha = 0.5 ) +
labs( title="Nonprofit Size (logged revenues)" ) +
xlab( variable.label ) +
facet_wrap( ~ rev.q, nrow=3 ) +
theme_minimal( base_size = 22 ) +
theme( axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank() )
ggplot( core2, aes(x = totnetassetend )) +
geom_density( alpha = 0.5) +
xlim( quantile(core2$totnetassetend, c(0.02,0.98), na.rm=T ) ) +
xlab( "Net Assets" ) +
theme( axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank() )
$totnetassetend[ core2$totnetassetend < 1 ] <- NA
core2
if( nrow(core2) > 10000 )
{<- sample_n( core2, 10000 )
core3 else
}
{<- core2
core3
}
jplot( log10(core3$totnetassetend), core3$selfsufficiency,
xlab="Nonprofit Size (logged Net Assets)",
ylab=variable.label,
xaxt="n", xlim=c(3,10) )
axis( side=1,
at=c(3,4,5,6,7,8,9,10),
labels=c("1k","10k","100k","1m","10m","100m","1b","10b") )
$totnetassetend[ core2$totnetassetend < 1 ] <- NA
core2$asset.q <- create_quantiles( var=core2$totnetassetend, n.groups=5 )
core2
%>%
core2 filter( ! is.na(asset.q) ) %>%
ggplot( aes(selfsufficiency) ) +
geom_density( alpha = 0.5 ) +
labs( title="Nonprofit Size (logged net assets, if assets > 0)" ) +
xlab( variable.label ) +
ylab( "" ) +
facet_wrap( ~ asset.q, nrow=3 ) +
theme_minimal( base_size = 22 ) +
theme( axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank() )
Total Assets for Comparison
$totassetsend[ core2$totassetsend < 1 ] <- NA
core2$tot.asset.q <- create_quantiles( var=core2$totassetsend, n.groups=5 )
core2
if( nrow(core2) > 10000 )
{<- sample_n( core2, 10000 )
core3 else
}
{<- core2
core3
}
jplot( log10(core3$totassetsend), core3$selfsufficiency,
xlab="Nonprofit Size (logged Total Assets)",
ylab=variable.label,
xaxt="n", xlim=c(3,10) )
axis( side=1,
at=c(3,4,5,6,7,8,9,10),
labels=c("1k","10k","100k","1m","10m","100m","1b","10b") )
ggplot( core2, aes(x = totassetsend )) +
geom_density( alpha = 0.5) +
xlim( quantile(core2$totassetsend, c(0.02,0.98), na.rm=T ) ) +
xlab( "Net Assets" ) +
theme( axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank() )
%>%
core2 filter( ! is.na(tot.asset.q) ) %>%
ggplot( aes(selfsufficiency) ) +
geom_density( alpha = 0.5 ) +
xlab( "Nonprofit Size (logged total assets, if assets > 0)" ) +
ylab( variable.label ) +
facet_wrap( ~ tot.asset.q, nrow=3 ) +
theme_minimal( base_size = 22 ) +
theme( axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank() )
ggplot( core2, aes(x = AGE )) +
geom_density( alpha = 0.5 )
$AGE[ core2$AGE < 1 ] <- NA
core2
if( nrow(core2) > 10000 )
{<- sample_n( core2, 10000 )
core3 else
}
{<- core2
core3
}
jplot( core3$AGE, core3$selfsufficiency,
xlab="Nonprofit Age",
ylab=variable.label )
%>%
core2 filter( ! is.na(age.q) ) %>%
ggplot( aes(selfsufficiency) ) +
geom_density( alpha = 0.5 ) +
labs( title="Nonprofit Age" ) +
xlab( variable.label ) +
ylab( "" ) +
facet_wrap( ~ age.q, nrow=3 ) +
theme_minimal( base_size = 22 ) +
theme( axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank() )
ggplot( core2, aes(x = lndbldgsequipend )) +
geom_density( alpha = 0.5 )
$lndbldgsequipend[ core2$lndbldgsequipend < 1 ] <- NA
core2if( nrow(core2) > 10000 )
{<- sample_n( core2, 10000 )
core3 else
}
{<- core2
core3
jplot( log10(core3$lndbldgsequipend), core3$selfsufficiency,
xlab="Land and Building Value (logged)",
ylab=variable.label,
xaxt="n", xlim=c(3,10) )
axis( side=1,
at=c(3,4,5,6,7,8,9,10),
labels=c("1k","10k","100k","1m","10m","100m","1b","10b") )
}
%>%
core2 filter( ! is.na(land.q) ) %>%
ggplot( aes(selfsufficiency) ) +
geom_density( alpha = 0.5 ) +
labs( title="Land and Building Value" ) +
xlab( variable.label ) +
ylab( "" ) +
facet_wrap( ~ land.q, nrow=3 ) +
theme_minimal( base_size = 22 ) +
theme( axis.title.y=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank() )
<- select( core, ein, tax_pd, selfsufficiency )
core.selfsufficiency saveRDS( core.selfsufficiency, "03-data-ratios/m-05-self-sufficiency-ratio.rds" )
write.csv( core.selfsufficiency, "03-data-ratios/m-05-self-suffiency-ratio.csv" )