Showing posts with label mental health. Show all posts
Showing posts with label mental health. Show all posts

Saturday, August 15, 2020

Pets and Quarantine

I'm so thankful to have my sweet boy, Zeppelin, in my life. And when quarantine/shelter-in-place began, I was especially thankful to have him, because otherwise, I would have been completely alone. Unsurprisingly, a recent study found I'm not the only one to feel this way:

Animal shelters across the country are being completely cleared out as people seek out creature comfort. In fact, more than one in four 18-37-year-olds with pets got their new friend during quarantine.1 Pets are bringing much-needed doses of positivity: two-thirds of Gen Z and Millennials living with pets agree their pet has helped them stay positive during this time.1

Pets are not only showing up in homes—we are seeing them brighten up our feeds, too. Online conversation around pet adoption spiked in mid-March, up 50% from the weekly average.5 Whether they have a furry friend or not, 80% of Gen Z and Millennials say seeing animal content on social media makes them happy, and 74% agree that they find comfort in animal content on social media.1 Additionally, pet-related hashtags such as #MeetMyPet, #PetRoutine, and #TreatYourPet have been trending on TikTok throughout the pandemic.

In fact, 68% of respondents said their pet helped them feel less alone, 65% said their pet helped them to "stay sane" during the pandemic, 54% believe having a pet has made them be healthier, and 39% said they'd been talking to their pet more during quarantine (guilty).

If you wish you had a four-legged friend during this difficult time, there are tons in need of a good home! I'm so glad this sweet guy is part of mine:


Friday, May 24, 2019

I'm More Sad About This Show Ending than Game of Thrones

Like many, I eagerly waited to see how the game of thrones would end. I tore through the books available at the time shortly before the first season of Game of Thrones aired, and look forward to reading how George R.R. Martin himself would write the ending of the story.

And like many, I was disappointed in the turns taken by Game of Thrones that felt inauthentic to the characters. Especially, this was a show that failed many of its female characters. They took Brienne, who we watched grow into a strong, independent, and honorable knight, and reduced her to Carrie F***ing Bradshaw. They justified the horrible things that had happened to Sansa as character-building. (No one can make you be someone you're not. Sansa, the strength was inside you all the time. Littlefinger and Ramsay don't get credit for that. If anyone does, it's the strong women in your life, like Brienne and Arya.)

But while I'm disappointed in how the show ended, and a little sad that it's gone, I'm honestly more sad that this show is over:


Who would have guessed that a musical comedy TV show would take on some very important issues with such authenticity? Here's just a few of them (some spoilers ahead, so read on only if you've watched the show or don't care about being spoiled):

Women's Issues
Just as a short list, this show tackled periods, abortion, women's sexuality, motherhood, and body image in a way that never felt cheap, judgmental, or cliché. It was the first network show to use the word "clitoris." The relationships between the women on the show felt real and the conversations were about more than simply the men in their lives. It didn't glamorize women's bodies - in fact, it pulled back the curtain on many issues related to women's appearance and projection of themselves to the world.



Men's Issues
The show didn't just represent women authentically - the men were fully realized characters too, and never props or plot devices. Crazy Ex-Girlfriend explored men's relationships, fatherhood, and toxic masculinity and how it affects men.


Mental Health
I could probably write an entire blog post just on how this show represents mental health issues. The main character, Rebecca Bunch, is diagnosed with borderline personality disorder in season 3. And in fact, the show was building up to and establishing that diagnosis from the very beginning. The show constantly made us rethink the word "crazy" and helped to normalize many mental health issues - and when I say normalize, I mean show us that these issues are common and experienced by many people, while still encouraging those struggling with mental health issues to seek help.


The show also tackled issues like low self-esteem, self-hatred, suicide, and alcoholism, without ever glamorizing them. Instead, it encouraged us to take better care of ourselves, and recognize when we have a problem we can't handle ourselves.



Bisexuality
When bisexuals show up in other movies or TV shows, they're often portrayed as promiscuous - people who are bi because they want to have sex with everyone. Either that, or they portray it, especially among men, as someone who is actually gay but not comfortable with coming fully out of the closet. Not Crazy Ex-Girlfriend.


Race and Ethnicity
This show has a diverse cast. And unlike many shows with "diversity," none of the characters are tokens. In fact, race and ethnicity aren't referenced so much as heritage. Further, the show pokes fun at the token concept. One great episode deals with Heather's ethnicity. Her boss, Kevin, encourages her to join a management training program because she is "diverse." Later, he gives her a gift to apologize for his insensitivity: a sari, because he assumes she is Indian. She corrects him; her father is African-American and her mother is White. The extra layer here is that the actress who plays Heather, Vella Lovell, has been mistakenly called Indian in the media, when she, like her character, is African-American and White. So this episode not only makes fun of the concept of the token, it also makes fun of the media trying so hard to ascertain and define an actor by her race.

Crazy Ex-Girlfriend, I'm really going to miss you.

Thursday, February 28, 2019

A New Trauma Population for the Social Media Age

Even if you aren't a Facebook use, you're probably aware that there are rules about what you can and cannot post. Images or videos that depict violence or illegal behavior would of course be taken down. But who decides that? You as a user can always report an image or video (or person or group) if you think it violates community standards. But obviously, Facebook doesn't want to traumatize its users if it can be avoided.

That's where the employees of companies like Cognizant come in. It's their job to watch some of the most disturbing content on the internet - and it's even worse than it sounds. In this fascinating article for The Verge, Casey Newton describes just how traumatic doing such a job can be. (Content warning - this post has lots of references to violence, suicide, and mental illness.)

The problem with the way these companies do business is that, not only do employees see violent and disturbing content; they also don't have the opportunity to talk about what they see with their support networks:
Over the past three months, I interviewed a dozen current and former employees of Cognizant in Phoenix. All had signed non-disclosure agreements with Cognizant in which they pledged not to discuss their work for Facebook — or even acknowledge that Facebook is Cognizant’s client. The shroud of secrecy is meant to protect employees from users who may be angry about a content moderation decision and seek to resolve it with a known Facebook contractor. The NDAs are also meant to prevent contractors from sharing Facebook users’ personal information with the outside world, at a time of intense scrutiny over data privacy issues.

But the secrecy also insulates Cognizant and Facebook from criticism about their working conditions, moderators told me. They are pressured not to discuss the emotional toll that their job takes on them, even with loved ones, leading to increased feelings of isolation and anxiety.

The moderators told me it’s a place where the conspiracy videos and memes that they see each day gradually lead them to embrace fringe views. One auditor walks the floor promoting the idea that the Earth is flat. A former employee told me he has begun to question certain aspects of the Holocaust. Another former employee, who told me he has mapped every escape route out of his house and sleeps with a gun at his side, said: “I no longer believe 9/11 was a terrorist attack.”
It's a fascinating read on an industry I really wasn't aware existed, and a population that could be diagnosed with PTSD and other responses to trauma.

Friday, April 27, 2018

X is for By

X is for By Today's post will be rather short, demonstrating a set of functions from the psych package, which allows you to conduct analysis by group. These commands add "By" to the end of existing functions. But first, a word of caution: With great power comes great responsibility. This function could very easily turn into a fishing expedition (also known as p-hacking). Conducting planned group comparisons is fine. Conducting all possible group comparisons and cherry-picking any differences is problematic. So use these group by functions with care.

Let's pull up the Facebook dataset for this.

Facebook<-read.delim(file="full_facebook_set.txt", header=TRUE)

This is the full dataset, which includes all the variables I collected. I don't want to run analyses on all variables, so I'll pull out the ones most important for this blog post demonstration.

smallFB<-Facebook[,c(1:2,77:80,105:116,122,133:137,170,187)]

First, I'll run descriptives on this smaller data frame by gender.

library(psych)
## Warning: package 'psych' was built under R version 3.4.4
describeBy(smallFB,smallFB$gender)
## 
##  Descriptive statistics by group 
## group: 0
##              vars  n      mean      sd   median   trimmed     mad      min
## RespondentId    1 73 164647.77 1711.78 164943.0 164587.37 2644.96 162373.0
## gender          2 73      0.00    0.00      0.0      0.00    0.00      0.0
## Rumination      3 73     37.66   14.27     37.0     37.41   13.34      8.0
## DepRelat        4 73     21.00    7.86     21.0     20.95    5.93      4.0
## Brood           5 73      8.49    3.76      9.0      8.42    2.97      1.0
## Reflect         6 73      8.16    4.44      8.0      8.24    4.45      0.0
## SavorPos        7 73     64.30   10.93     65.0     64.92    8.90     27.0
## SavorNeg        8 73     33.30   11.48     33.0     33.08   13.34     12.0
## SavorTot        9 73     31.00   20.15     34.0     31.15   19.27    -10.0
## AntPos         10 73     20.85    3.95     21.0     20.93    4.45     10.0
## AntNeg         11 73     11.30    4.23     11.0     11.22    4.45      4.0
## AntTot         12 73      9.55    6.90     10.0      9.31    7.41     -3.0
## MomPos         13 73     21.68    3.95     22.0     21.90    2.97      9.0
## MomNeg         14 73     11.45    4.63     11.0     11.41    5.93      4.0
## MomTot         15 73     10.23    7.63     11.0     10.36    8.90    -11.0
## RemPos         16 73     21.77    4.53     23.0     22.20    4.45      8.0
## RemNeg         17 73     10.55    4.39      9.0     10.27    4.45      4.0
## RemTot         18 73     11.22    8.05     14.0     11.68    7.41     -8.0
## LifeSat        19 73     24.63    6.80     25.0     24.93    7.41     10.0
## Extravert      20 73      4.32    1.58      4.5      4.33    1.48      1.5
## Agreeable      21 73      4.79    1.08      5.0      4.85    1.48      1.0
## Conscient      22 73      5.14    1.34      5.0      5.19    1.48      2.0
## EmotStab       23 73      5.10    1.22      5.0      5.15    1.48      1.0
## OpenExp        24 73      5.11    1.29      5.5      5.20    1.48      2.0
## Health         25 73     28.77   19.56     25.0     26.42   17.79      0.0
## Depression     26 73     10.26    7.27      9.0      9.56    5.93      0.0
##                 max  range  skew kurtosis     se
## RespondentId 168279 5906.0  0.21    -1.36 200.35
## gender            0    0.0   NaN      NaN   0.00
## Rumination       71   63.0  0.12    -0.53   1.67
## DepRelat         42   38.0  0.10    -0.04   0.92
## Brood            17   16.0  0.15    -0.38   0.44
## Reflect          19   19.0 -0.12    -0.69   0.52
## SavorPos         84   57.0 -0.69     0.76   1.28
## SavorNeg         57   45.0  0.14    -0.95   1.34
## SavorTot         72   82.0 -0.17    -0.75   2.36
## AntPos           28   18.0 -0.24    -0.46   0.46
## AntNeg           22   18.0  0.27    -0.55   0.49
## AntTot           24   27.0  0.11    -0.76   0.81
## MomPos           28   19.0 -0.69     0.55   0.46
## MomNeg           22   18.0  0.08    -0.98   0.54
## MomTot           24   35.0 -0.25    -0.55   0.89
## RemPos           28   20.0 -0.88     0.35   0.53
## RemNeg           22   18.0  0.56    -0.66   0.51
## RemTot           24   32.0 -0.53    -0.77   0.94
## LifeSat          35   25.0 -0.37    -0.84   0.80
## Extravert         7    5.5 -0.09    -0.93   0.19
## Agreeable         7    6.0 -0.60     1.04   0.13
## Conscient         7    5.0 -0.24    -0.98   0.16
## EmotStab          7    6.0 -0.60     0.28   0.14
## OpenExp           7    5.0 -0.49    -0.55   0.15
## Health           91   91.0  1.13     1.14   2.29
## Depression       36   36.0  1.02     0.95   0.85
## -------------------------------------------------------- 
## group: 1
##              vars   n      mean      sd    median   trimmed     mad
## RespondentId    1 184 164373.49 1515.34 164388.00 164253.72 1891.80
## gender          2 184      1.00    0.00      1.00      1.00    0.00
## Rumination      3 184     38.09   15.28     40.00     38.16   17.05
## DepRelat        4 184     21.67    8.78     21.00     21.66    8.90
## Brood           5 184      8.57    4.14      8.50      8.47    3.71
## Reflect         6 184      7.84    4.06      8.00      7.73    4.45
## SavorPos        7 184     67.22    9.63     68.00     67.71    8.90
## SavorNeg        8 184     29.75   11.62     27.50     28.72    9.64
## SavorTot        9 184     37.47   19.30     40.00     38.66   20.02
## AntPos         10 184     22.18    3.37     23.00     22.28    2.97
## AntNeg         11 184     10.10    4.44      9.00      9.78    4.45
## AntTot         12 184     12.08    6.85     14.00     12.36    5.93
## MomPos         13 184     22.28    3.88     23.00     22.59    2.97
## MomNeg         14 184     10.60    4.88      9.50     10.13    5.19
## MomTot         15 184     11.68    7.75     13.00     12.29    7.41
## RemPos         16 184     22.76    3.85     23.00     23.10    2.97
## RemNeg         17 184      9.05    3.79      8.00      8.68    2.97
## RemTot         18 184     13.71    6.97     15.00     14.34    5.93
## LifeSat        19 184     23.76    6.25     24.00     24.18    7.41
## Extravert      20 184      4.66    1.57      5.00      4.74    1.48
## Agreeable      21 184      5.22    1.06      5.50      5.26    1.48
## Conscient      22 184      5.32    1.24      5.50      5.42    1.48
## EmotStab       23 184      4.70    1.31      4.75      4.75    1.11
## OpenExp        24 184      5.47    1.08      5.50      5.56    0.74
## Health         25 184     32.54   16.17     30.00     31.43   16.31
## Depression     26 184     12.19    8.48      9.00     11.09    5.93
##                   min    max  range  skew kurtosis     se
## RespondentId 162350.0 167714 5364.0  0.46    -0.90 111.71
## gender            1.0      1    0.0   NaN      NaN   0.00
## Rumination        3.0     74   71.0 -0.05    -0.60   1.13
## DepRelat          0.0     42   42.0  0.00    -0.46   0.65
## Brood             0.0     19   19.0  0.19    -0.62   0.31
## Reflect           0.0     19   19.0  0.25    -0.48   0.30
## SavorPos         33.0     84   51.0 -0.59     0.36   0.71
## SavorNeg         12.0     64   52.0  0.79     0.25   0.86
## SavorTot        -18.0     72   90.0 -0.57    -0.10   1.42
## AntPos            9.0     28   19.0 -0.49     0.41   0.25
## AntNeg            4.0     22   18.0  0.63    -0.39   0.33
## AntTot           -8.0     24   32.0 -0.43    -0.48   0.50
## MomPos           10.0     28   18.0 -0.81     0.54   0.29
## MomNeg            4.0     24   20.0  0.81    -0.03   0.36
## MomTot          -13.0     24   37.0 -0.69    -0.03   0.57
## RemPos            9.0     28   19.0 -0.87     0.81   0.28
## RemNeg            4.0     21   17.0  0.83     0.33   0.28
## RemTot           -9.0     24   33.0 -0.82     0.50   0.51
## LifeSat           8.0     35   27.0 -0.53    -0.32   0.46
## Extravert         1.0      7    6.0 -0.36    -0.72   0.12
## Agreeable         2.5      7    4.5 -0.27    -0.63   0.08
## Conscient         1.0      7    6.0 -0.70     0.13   0.09
## EmotStab          1.5      7    5.5 -0.35    -0.73   0.10
## OpenExp           1.5      7    5.5 -0.91     0.62   0.08
## Health            2.0     85   83.0  0.60    -0.05   1.19
## Depression        0.0     39   39.0  1.14     0.66   0.62

In this dataset, I coded men as 0 and women as 1. The descriptive statistics table generated includes all scale and subscale scores, and gives me mean, standard deviation, median, a trimmed mean (dropping very low and very high values), median absolute deviation, minimum and maximum values, range, skewness, and kurtosis. I'd need to run t-tests to find out if differences were significant, but this still gives me some idea of how men and women might differ on these measures.

There are certain measures I included that we might hypothesize would show gender differences. For instance, some research suggests gender differences for rumination and depression. In addition to running descriptives by group, I might also want to display these differences in a violin plot. The psych package can quickly generate such a plot by group.

violinBy(smallFB,"Rumination","gender",grp.name=c("M","F"))
violinBy(smallFB,"Depression","gender",grp.name=c("M","F"))

ggplot2 will generate a violin plot by group, so this feature might not be as useful for final displays, but could help in quickly visualizing the data during analysis. And you may find that you prefer the appearance of this plots. To each his own.

Another function is error.bars.by, which plots means and confidence intervals by group for multiple variables. Again, this is a way to get some quick visuals, though differences in scale among measures should be taken into consideration when generating this plot. One set of variables for which this display might be useful is the 5 subscales of the Five-Factor Personality Inventory. This 10-item measure assesses where participants fall on the so-called Big Five personality traits: Openness to Experience, Conscientiousness, Extraversion, Agreeableness, and Neuroticism (Emotional Stability). These subscales are all on the same metric.

error.bars.by(smallFB[,c(20:24)],group=smallFB$gender,xlab="Big Five Personality Traits",ylab="Score on Subscale")

Finally, we have the statsBy function, which gives descriptive statistics by group as well as between group statistics. This functions generates a lot of output, and you can read more about everything it gives you here.
FBstats<-statsBy(smallFB[,2:26],"gender",cors=TRUE,method="pearson",use="pairwise")
print(FBstats,short=FALSE)
## Statistics within and between groups  
## Call: statsBy(data = smallFB[, 2:26], group = "gender", cors = TRUE, 
##     method = "pearson", use = "pairwise")
## Intraclass Correlation 1 (Percentage of variance due to groups) 
##     gender Rumination   DepRelat      Brood    Reflect   SavorPos 
##       1.00      -0.01      -0.01      -0.01      -0.01       0.03 
##   SavorNeg   SavorTot     AntPos     AntNeg     AntTot     MomPos 
##       0.03       0.04       0.05       0.02       0.05       0.00 
##     MomNeg     MomTot     RemPos     RemNeg     RemTot    LifeSat 
##       0.00       0.01       0.02       0.05       0.04       0.00 
##  Extravert  Agreeable  Conscient   EmotStab    OpenExp     Health 
##       0.01       0.05       0.00       0.03       0.03       0.01 
## Depression 
##       0.01 
## Intraclass Correlation 2 (Reliability of group differences) 
##     gender Rumination   DepRelat      Brood    Reflect   SavorPos 
##       1.00     -22.34      -2.06     -50.93      -2.21       0.77 
##   SavorNeg   SavorTot     AntPos     AntNeg     AntTot     MomPos 
##       0.80       0.83       0.86       0.75       0.86       0.19 
##     MomNeg     MomTot     RemPos     RemNeg     RemTot    LifeSat 
##       0.39       0.46       0.68       0.87       0.84      -0.04 
##  Extravert  Agreeable  Conscient   EmotStab    OpenExp     Health 
##       0.60       0.88       0.05       0.80       0.81       0.60 
## Depression 
##       0.66 
## eta^2 between groups  
## Rumination.bg   DepRelat.bg      Brood.bg    Reflect.bg   SavorPos.bg 
##          0.00          0.00          0.00          0.00          0.02 
##   SavorNeg.bg   SavorTot.bg     AntPos.bg     AntNeg.bg     AntTot.bg 
##          0.02          0.02          0.03          0.02          0.03 
##     MomPos.bg     MomNeg.bg     MomTot.bg     RemPos.bg     RemNeg.bg 
##          0.00          0.01          0.01          0.01          0.03 
##     RemTot.bg    LifeSat.bg  Extravert.bg  Agreeable.bg  Conscient.bg 
##          0.02          0.00          0.01          0.03          0.00 
##   EmotStab.bg    OpenExp.bg     Health.bg Depression.bg 
##          0.02          0.02          0.01          0.01 
## Correlation between groups 
##               Rmnt. DpRl. Brd.b Rflc. SvrP. SvrN. SvrT. AntP. AntN. AntT.
## Rumination.bg  1                                                         
## DepRelat.bg    1     1                                                   
## Brood.bg       1     1     1                                             
## Reflect.bg    -1    -1    -1     1                                       
## SavorPos.bg    1     1     1    -1     1                                 
## SavorNeg.bg   -1    -1    -1     1    -1     1                           
## SavorTot.bg    1     1     1    -1     1    -1     1                     
## AntPos.bg      1     1     1    -1     1    -1     1     1               
## AntNeg.bg     -1    -1    -1     1    -1     1    -1    -1     1         
## AntTot.bg      1     1     1    -1     1    -1     1     1    -1     1   
## MomPos.bg      1     1     1    -1     1    -1     1     1    -1     1   
## MomNeg.bg     -1    -1    -1     1    -1     1    -1    -1     1    -1   
## MomTot.bg      1     1     1    -1     1    -1     1     1    -1     1   
## RemPos.bg      1     1     1    -1     1    -1     1     1    -1     1   
## RemNeg.bg     -1    -1    -1     1    -1     1    -1    -1     1    -1   
## RemTot.bg      1     1     1    -1     1    -1     1     1    -1     1   
## LifeSat.bg    -1    -1    -1     1    -1     1    -1    -1     1    -1   
## Extravert.bg   1     1     1    -1     1    -1     1     1    -1     1   
## Agreeable.bg   1     1     1    -1     1    -1     1     1    -1     1   
## Conscient.bg   1     1     1    -1     1    -1     1     1    -1     1   
## EmotStab.bg   -1    -1    -1     1    -1     1    -1    -1     1    -1   
## OpenExp.bg     1     1     1    -1     1    -1     1     1    -1     1   
## Health.bg      1     1     1    -1     1    -1     1     1    -1     1   
## Depression.bg  1     1     1    -1     1    -1     1     1    -1     1   
##               MmPs. MmNg. MmTt. RmPs. RmNg. RmTt. LfSt. Extr. Agrb. Cnsc.
## MomPos.bg      1                                                         
## MomNeg.bg     -1     1                                                   
## MomTot.bg      1    -1     1                                             
## RemPos.bg      1    -1     1     1                                       
## RemNeg.bg     -1     1    -1    -1     1                                 
## RemTot.bg      1    -1     1     1    -1     1                           
## LifeSat.bg    -1     1    -1    -1     1    -1     1                     
## Extravert.bg   1    -1     1     1    -1     1    -1     1               
## Agreeable.bg   1    -1     1     1    -1     1    -1     1     1         
## Conscient.bg   1    -1     1     1    -1     1    -1     1     1     1   
## EmotStab.bg   -1     1    -1    -1     1    -1     1    -1    -1    -1   
## OpenExp.bg     1    -1     1     1    -1     1    -1     1     1     1   
## Health.bg      1    -1     1     1    -1     1    -1     1     1     1   
## Depression.bg  1    -1     1     1    -1     1    -1     1     1     1   
##               EmtS. OpnE. Hlth. Dprs.
## EmotStab.bg    1                     
## OpenExp.bg    -1     1               
## Health.bg     -1     1     1         
## Depression.bg -1     1     1     1   
## Correlation within groups 
##               Rmnt. DpRl. Brd.w Rflc. SvrP. SvrN. SvrT. AntP. AntN. AntT.
## Rumination.wg  1.00                                                      
## DepRelat.wg    0.95  1.00                                                
## Brood.wg       0.88  0.78  1.00                                          
## Reflect.wg     0.80  0.63  0.59  1.00                                    
## SavorPos.wg   -0.20 -0.20 -0.18 -0.15  1.00                              
## SavorNeg.wg    0.43  0.43  0.36  0.30 -0.64  1.00                        
## SavorTot.wg   -0.36 -0.36 -0.31 -0.25  0.89 -0.92  1.00                  
## AntPos.wg     -0.06 -0.05 -0.08 -0.03  0.86 -0.49  0.73  1.00            
## AntNeg.wg      0.32  0.32  0.28  0.21 -0.54  0.89 -0.80 -0.50  1.00      
## AntTot.wg     -0.23 -0.23 -0.21 -0.15  0.78 -0.82  0.89  0.83 -0.89  1.00
## MomPos.wg     -0.26 -0.26 -0.22 -0.19  0.86 -0.60  0.80  0.60 -0.47  0.61
## MomNeg.wg      0.46  0.46  0.39  0.35 -0.51  0.88 -0.78 -0.33  0.66 -0.59
## MomTot.wg     -0.42 -0.42 -0.36 -0.32  0.75 -0.85  0.89  0.51 -0.65  0.68
## RemPos.wg     -0.20 -0.19 -0.17 -0.15  0.89 -0.56  0.79  0.66 -0.44  0.62
## RemNeg.wg      0.34  0.35  0.28  0.23 -0.65  0.87 -0.85 -0.49  0.69 -0.69
## RemTot.wg     -0.29 -0.30 -0.25 -0.21  0.85 -0.79  0.90  0.63 -0.62  0.72
## LifeSat.wg    -0.47 -0.47 -0.43 -0.31  0.54 -0.50  0.57  0.39 -0.33  0.41
## Extravert.wg  -0.20 -0.19 -0.11 -0.20  0.34 -0.35  0.38  0.21 -0.29  0.29
## Agreeable.wg  -0.18 -0.18 -0.20 -0.10  0.35 -0.45  0.45  0.28 -0.39  0.39
## Conscient.wg  -0.25 -0.30 -0.20 -0.10  0.24 -0.21  0.25  0.16 -0.14  0.17
## EmotStab.wg   -0.48 -0.44 -0.49 -0.34  0.34 -0.44  0.43  0.20 -0.33  0.32
## OpenExp.wg    -0.16 -0.14 -0.21 -0.10  0.37 -0.31  0.37  0.27 -0.27  0.31
## Health.wg      0.44  0.47  0.36  0.29 -0.30  0.34 -0.35 -0.21  0.26 -0.27
## Depression.wg  0.57  0.58  0.49  0.38 -0.44  0.55 -0.55 -0.27  0.39 -0.39
##               MmPs. MmNg. MmTt. RmPs. RmNg. RmTt. LfSt. Extr. Agrb. Cnsc.
## MomPos.wg      1.00                                                      
## MomNeg.wg     -0.56  1.00                                                
## MomTot.wg      0.86 -0.91  1.00                                          
## RemPos.wg      0.65 -0.42  0.59  1.00                                    
## RemNeg.wg     -0.55  0.63 -0.67 -0.65  1.00                              
## RemTot.wg      0.66 -0.58  0.69  0.91 -0.91  1.00                        
## LifeSat.wg     0.55 -0.55  0.62  0.48 -0.42  0.49  1.00                  
## Extravert.wg   0.39 -0.37  0.43  0.28 -0.25  0.29  0.27  1.00            
## Agreeable.wg   0.33 -0.43  0.43  0.31 -0.36  0.37  0.25  0.12  1.00      
## Conscient.wg   0.25 -0.16  0.22  0.23 -0.26  0.26  0.33  0.03  0.29  1.00
## EmotStab.wg    0.40 -0.50  0.51  0.27 -0.32  0.32  0.44  0.12  0.41  0.27
## OpenExp.wg     0.39 -0.26  0.36  0.30 -0.28  0.32  0.34  0.29  0.36  0.14
## Health.wg     -0.30  0.33 -0.36 -0.27  0.29 -0.31 -0.42 -0.10 -0.25 -0.24
## Depression.wg -0.45  0.56 -0.58 -0.41  0.49 -0.50 -0.65 -0.24 -0.29 -0.26
##               EmtS. OpnE. Hlth. Dprs.
## EmotStab.wg    1.00                  
## OpenExp.wg     0.24  1.00            
## Health.wg     -0.31 -0.18  1.00      
## Depression.wg -0.54 -0.28  0.56  1.00
## 
## Many results are not shown directly. To see specific objects select from the following list:
##  mean sd n F ICC1 ICC2 ci1 ci2 r within pooled sd.r raw rbg pbg rwg nw pwg etabg etawg nwg nG Call

The variance explained by gender is quite small for all of the variables. Instead, the relationships between the variables seem to be more meaningful.

A to Z is almost done! Just Y and Z, plus look for an A-to-Z-influenced Statistics Sunday post!

Thursday, April 26, 2018

Predictive Analytics and Veteran Suicide Prevention

One of the best things about working for the Department of Veterans Affairs was the vast amount of data available on Veterans receiving care through VA. While my research center often used surveys, focus groups, and interviews to collect data on Veterans, we frequently pulled in data from Veterans' medical records (with their permission, of course). And other researchers were accessing Veteran data directly to understand and improve care.

An issue we frequently heard about, and sometimes dealt with firsthand, was the high rate of suicide among our Veterans. Veterans are at high risk for many physical and mental conditions, and are at heightened risk for suicide. The National Suicide Prevention Lifeline was created to help anyone, including Veterans, who is feeling helpless. Through partnerships with VA and other federal agencies, we heard about many success stories of the Lifeline.

But with the vast amount of data available on our Veterans, it would be great if we could intervene and help before someone gets to the crisis point. Today, I read about how the REACH Vet program is using predictive analytics to identify Veterans at risk for suicide:
The REACH Vet program draws on the agency’s vast trove of electronic health records and uses predictive analytics to identify patients who might be at risk of suicide. It alerts VA clinicians of veterans who could benefit from more attention, and the program prompts clinicians to call and check in with their patients.

“What we found … not surprisingly is that veterans at highest risk of suicide are also at very high risk of some other things,” Aaron Eagan, VA’s deputy director for innovation, said Thursday at ACT-IAC’s Health Innovation Day in Washington. “They’re at significantly increased rates of all-cause mortality, accident morality, overdoses, violence … [and] opioids.”

Veterans who engaged with REACH Vet were admitted to mental health inpatient units less often, showed up to more mental health and primary care appointments and visited the VA more frequently, compared to veterans who weren’t part of the program.

Eagan said he expected veterans would be frustrated by the phone calls, but his team hasn’t gotten any complaints.

“It’s a great reminder that people really feel good about us caring about them, and that’s what the response generally is,” he said.

The REACH Vet team is updating its predictive model for the program now, and it’s starting a new collaboration with the Energy Department’s super computer, Eagan said.
 

Sunday, April 22, 2018

Statistics Sunday: Using semPlot

using semPlot with Facebook Models Today's post will be mostly demonstration, but I'll build on some of the things I covered in yesterday's semPlot post. This month, I've blogged about two SEM models: confirmatory factor analysis and latent variable path analysis. Using the models from those posts, I'll show how to diagram them in semPlot and how to make some changes to the appearance of the plots to make them presentation ready.

Facebook<-read.delim(file="small_facebook_set.txt", header=TRUE)

First up, confirmatory factor analysis. As part of that post, I tested models with the Satisfaction with Life Scale and Ruminative Response Scale. In fact, I gave a sneak preview of semPlot with the SWLS model.

SWL_Model<-'SWL =~ LS1 + LS2 + LS3 + LS4 + LS5'
library(lavaan)
## This is lavaan 0.5-23.1097
## lavaan is BETA software! Please report any bugs.
SWL_Fit<-cfa(SWL_Model, data=Facebook)
library(semPlot)
semPaths(SWL_Fit)

This diagram is fine to quickly show what the model looks like, but we want to tweak it if we were to use it for a presentation or publication. First up, I used very abbreviated variable names, so semPlot is having no trouble displaying all of it in the diagram. But I might want more descriptive names for my variables, and I probably want to do that without having to rename variables or rewrite my model.

labels<-c("Ideal Life","Excellent","Satisfied","Important","Change","SWL\nScale")
semPaths(SWL_Fit,nodeLabels=labels,sizeMan=10)

I've selected a keyword (or two) for each SWLS item, and made that the variable name. For instance, item 1 text is, "In most ways, my life is close to ideal." When creating your labels object, you want to put the y-variables in the order in which they appear in the equation(s), followed by x-variables, again in the order in which they appear.

We probably want to add a title and our parameter estimates. I'll use standardized estimates, since these are a bit easier to interpret. But there are a few other changes I'd like to make. semPlot automatically fades based on size of the parameter estimates, so larger estimates are darker than smaller estimates. It also changes the width of paths based on size, including for error estimates; so larger error means a thicker, darker line. Fortunately, I can turn these features off. I can also change the size of the arrowheads. (BTW, Man refers to manifest (or observed) variables, and Lat refers to latent variables (or factors); so these size arguments change the width of observed and latent variables, respectively.)

semPaths(SWL_Fit,what="std",edge.label.cex=0.75,edge.color="black",
nodeLabels=labels,sizeMan=10,sizeLat=10,fade=FALSE,esize=2,asize=2) title("Diener Satisfaction with Life Scale CFA", line=3)

Feel free to play around with the numbers I've selected to see how it affects the final look.

But then, the Satisfaction with Life Scale is a short measure and this is a small, simple model. What happens if I throw a much larger model at semPlot? Including full labels for the observed variables might overwhelm a large model, so I may simple want to use item number only and only label the factor.

RRS_Model<- '
  Depression =~ Rum1 + Rum2 + Rum3 + Rum4 + Rum6 + Rum8 + 
    Rum9 + Rum14 + Rum17 + Rum18 + Rum19 + Rum22
  Reflecting =~ Rum7 + Rum11 + Rum12 + Rum20 + Rum21
  Brooding =~ Rum5 + Rum10 + Rum13 + Rum15 + Rum16
'
RRS_Fit<-cfa(RRS_Model, data=Facebook)
rrslabels<-c(1:4,6,8,9,14,17:19,22,7,11,12,20,21,5,10,13,15,16,"Depression",
"Reflecting","Brooding") RRS<-semPaths(RRS_Fit,what="par",whatLabels="hide",nodeLabels=rrslabels, sizeLat=12, sizeMan=4.5,edge.label.cex=0.75, edge.color="black", asize=2)

Adding estimates to this diagram would probably make it difficult to read, so personally, I would probably also create a table with the actual parameter estimates and use the diagram for display purposes only. Instead, I allowed fading, so that stronger relationships would be darker than weaker relationships. This is done by asking it to include parameter estimate (what="par") but then to hide those labels (whatLabels="hide").

What about for even more complex models, like a latent variable path model? In that post, I tested a structural regression with rumination and depression.

Rum3_Dep<-'
Depression =~ Dep1 + Dep2 + Dep3 + Dep4 + Dep5 + Dep6 + Dep7 + Dep8 +
              Dep9 + Dep10 + Dep11 + Dep12 + Dep13 + Dep14 + Dep15 + Dep16
DRR =~ Rum1 + Rum2 + Rum3 + Rum4 + Rum6 + Rum8 + Rum9 + Rum14 + Rum17 + Rum18 + 
              Rum19 + Rum22
Reflecting =~ Rum7 + Rum11 + Rum12 + Rum20 + Rum21
Brooding =~ Rum5 + Rum10 + Rum13 + Rum15 + Rum16
Depression ~ DRR + Reflecting + Brooding
'
RD3<-sem(Rum3_Dep, data=Facebook)
semPaths(RD3)

For this type of model, I tend prefer a different rotation, with the x-variables on the left and the y-variables on the right. I also want to customize my labels. Remember, y goes before x, but observed go before latent, so the order is: y-observed, x-observed, y-latent, x-latent. I may also use Lisrel style errors, which are simple arrows rather than curved double-pointed arrows, and may change the appearance of the covariances for the exogenous latent variables, so they don't get as lost.
rrsdlabels<-c(1:16,1:4,6,8,9,14,17:19,22,7,11,12,20,21,5,10,13,15,16,"Depression",
"Dep-Related","Reflecting","Brooding") semPaths(RD3, rotation=2,nodeLabels=rrsdlabels,sizeMan=3,
style="lisrel",curvePivot=TRUE, edge.color="black", ) title("Rumination and Depression Structural Regression Model")

If all paths are significant, it's okay not to have parameter estimates or fading displayed. I used fading for the measurement model, but I could just have easily done this instead: added additional text indicating that everything is significant. Pretend for the sake of argument that this is true for this model. We could easily add this descriptive text on the model drawing.

semPaths(RD3, rotation=2,nodeLabels=rrsdlabels,sizeMan=3,style="lisrel",
curvePivot=TRUE, edge.color="black") title("Rumination and Depression Structural Regression Model") text(0,-.9,"All paths and variances significant, p<0.05")

Either approach is fine - it really depends on what information you want to communicate. Do you want to demonstrate which items best measure the underlying construct? Or do you simply want to show that all items significantly contribute to the measurement of the construct? The same goes for LVPA; do you want to show what variables are the strongest predictors or just that all variables are significant predictors? In this particular case, not all paths are significant - brooding and reflecting do not significantly predict depression. So I may want a different approach to highlight this fact.

semPaths(RD3, rotation=2,nodeLabels=rrsdlabels,sizeMan=3,style="lisrel",
curvePivot=TRUE, edge.color="black", what="par",whatLabels="hide",) title("Rumination and Depression Structural Regression Model")

With the fading on, we see that Depression-Related Rumination is the strongest predictor of Depression. Reflecting is the weakest predictor, but both brooding and reflecting are non-significant, and the paths are very light.

Back to A to Z posts tomorrow, where I'll talk about a new data structure - tibbles!

Thursday, April 19, 2018

Q is for qplot

Q is for qplot You may have noticed that I frequently use the ggplot2 package and the ggplot function to produce graphics for my posts. ggplot2, which is part of the so-called tidyverse, is called gg to refer to the "grammar of graphics". That is, it uses standard functions and arguments to produce any number of graphics. You can change the appearance of these graphics by applying different settings. The nice thing about this type of syntax is that once you learn it for one type of graphic - say a histogram - it's very easy to expand out to other types of graphics - like scatterplots - without having to learn brand new functions. ggplot is a great way to create high-quality, publication-ready graphics.

But sometimes you don't need high-quality, publication-ready. Sometimes you just need a quick look at the data and you don't care if you have axis labels or centered titles. You just need to make certain there isn't anything wonky about your data as you clean and/or analyze. Fortunately, ggplot2 has a great function for that - qplot (or quick plot).

As with ggplot, qplot has a standard function and set of arguments, so once you learn to do it for one type of graphic, you can easily expand to others. And qplot has some smart rules built in to default to two of the most frequently used charts (particularly for quick looks at the data): histograms and scatterplots. Why are these most frequently used, especially in cleaning and early stages of analysis? A histogram lets you see if your variable is approximately normal; this is important because many statistical tests (and most of them you would have learned in an Introductory Statistics course) are built on the assumption that data are normally distributed. A scatterplot lets you see if your variables are related to each other, and whether that relationship is linear or not; once again, many statistical tests are built on assumptions about linear relationships between variables. So it makes sense that, if you're taking a quick look, you'll probably be using one of these two graphics.

The default graphics are very easy to produce: if you give only an x variable, you'll get a histogram, and if you give both x and y, you'll get a scatterplot. I'll use the Facebook data once again to demonstrate. I also went ahead and scored the RRS and SBI (described below) here - you can find code for scoring all measures here.

Facebook<-read.delim(file="small_facebook_set.txt", header=TRUE)
Facebook$RRS<-rowSums(Facebook[,3:24])
reverse<-function(max,min,x) {
  y<-(max+min)-x
  return(y)
}
Facebook$Sav2R<-reverse(7,1,Facebook$Sav2)
Facebook$Sav4R<-reverse(7,1,Facebook$Sav4)
Facebook$Sav6R<-reverse(7,1,Facebook$Sav6)
Facebook$Sav8R<-reverse(7,1,Facebook$Sav8)
Facebook$Sav10R<-reverse(7,1,Facebook$Sav10)
Facebook$Sav12R<-reverse(7,1,Facebook$Sav12)
Facebook$Sav14R<-reverse(7,1,Facebook$Sav14)
Facebook$Sav16R<-reverse(7,1,Facebook$Sav16)
Facebook$Sav18R<-reverse(7,1,Facebook$Sav18)
Facebook$Sav20R<-reverse(7,1,Facebook$Sav20)
Facebook$Sav22R<-reverse(7,1,Facebook$Sav22)
Facebook$Sav24R<-reverse(7,1,Facebook$Sav24)
Facebook$SBI<-Facebook$Sav2R+Facebook$Sav4R+Facebook$Sav6R+
  Facebook$Sav8R+Facebook$Sav10R+Facebook$Sav12R+Facebook$Sav14R+
  Facebook$Sav16R+Facebook$Sav18R+Facebook$Sav20R+Facebook$Sav22R+
  Facebook$Sav24R+Facebook$Sav1+Facebook$Sav3+Facebook$Sav5+
  Facebook$Sav7+Facebook$Sav9+Facebook$Sav11+Facebook$Sav13+Facebook$Sav15+
  Facebook$Sav17+Facebook$Sav19+Facebook$Sav21+Facebook$Sav23
library(ggplot2)

I'll use a scale I haven't really used in this series - the Savoring Beliefs Inventory. This measure was created by Fred Bryant, who was my faculty sponsor for this research (since I was still a grad student at the time). Fred also taught me structural equation modeling. The measure assesses a concept Fred calls savoring - fixating on positive events and feelings to retain those feelings of joy and pleasure. I selected this measure to include because, as I mentioned to Fred, I felt savoring was the opposite of rumination. (While he thought I'd made a good point, he told me he thought of savoring as the opposite of coping, which makes sense.)

Using the qplot function, we can quickly generate a histogram with total SBI score.

qplot(SBI, data=Facebook)
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

This variable shows a negative skew: there is a long tail (fewer cases than we'd expect if this followed the normal distribution) at the low end, the highest part of the distribution is to the right of center, and there is much less of a tail at the high end (more cases than we'd expect if this followed the normal distribution). We're also getting a message about bins. Right now, the histogram is slicing up the values between the minimum and the maximum into 30 bars. We can reduce this number to smooth out the distribution.

qplot(SBI, data=Facebook, bins=15)

This helps make the shape of the distribution more clear - we have a definite negative skew.

Now, regardless of whether the psychological opposite of savoring is coping or rumination, Fred and I both agreed that savoring and rumination would be negatively correlated. We can quickly demonstrate this, thanks to qplot with two variables.

qplot(SBI, RRS, data=Facebook)
cor(Facebook$SBI, Facebook$RRS)
## [1] -0.3510101

I also requested the correlation coefficient for these two variables, which is -0.35. This is a moderate negative correlation.

There are many other things you can do with qplot. First, you could generate separate graphics for groups, using facets.

Facebook$gender<-factor(Facebook$gender, labels=c("Male","Female"))
qplot(SBI, RRS, data=Facebook, facets=~gender)

Alternatively, we could have men and women points displayed on the chart in different colors.

qplot(SBI, RRS, data=Facebook, colour=gender)

You can also change the type of graphic with geom.

qplot(gender, data=Facebook, geom="bar")

There are other things you can do, such as manually set the limits for the x- or y-axes (with xlim=c(min,max) or ylim=c(min,max)), or log transform one or both variables. To demonstrate the latter, I'll bring back in my power analysis dataset - projected sample sizes for proportion comparisons with power of 0.8 or 0.9. I could have log-transformed the sample size variable.

library(pwr)
## Warning: package 'pwr' was built under R version 3.4.4
p1s <- seq(.5,.79,.01)
h <- ES.h(p1 = p1s, p2 = 0.80)
nh <- length(h)
p <- c(.8,.9)
np <- length(p)
sizes <- array(numeric(nh*np), dim=c(nh,np))
for (i in 1:np){
   for (j in 1:nh){
       pow_an <- pwr.p.test(n = NULL, h = h[j],
                            sig.level = .05, power = p[i],
                            alternative = "less")
       sizes[j,i] <- ceiling(pow_an$n)
   }
}
samp <- data.frame(cbind(p1s,sizes))
colnames(samp)<-c("Pass_Rate","Power.8", "Power.9")
qplot(Pass_Rate, Power.9, data=samp, log="y", ylab="Log-Transformed Sample Size")

As you can see, I can add custom labels - by default, it displays variable names, which is fine for a quick look. But I wanted to specifically call-out that y was log-transformed so my little brain didn't get confused if I had to walk away and come back.

Tomorrow will be a code-free post giving a short history of R. And back to coding posts Saturday!

Wednesday, April 18, 2018

P is for Principal Components Analysis (PCA)

P is for Principal Components Analysis This month, I've talked about some approaches for testing the underlying latent variables (or factors) in a set of measurement data. Confirmatory factor analysis is one method of examining latent variables when you know ahead of time which observed variables are associated with which factor. But it isn't the only way to do this. Sometimes you need to test for the presence of latent variables. Exploratory factor analysis is one way, but if I'm doing exploratory latent variable analysis, I tend to prefer using an approach called principal components analysis instead.

Both principal components analysis and exploratory factor analysis have the goal of reducing the amount of data you have to work with, by looking for how individual observed variables hang together. While exploratory factor analysis has the goal of explaining why observed variables relate to each other (because of the influence of the latent variable on the observed variables), principal components analysis has the goal of simply describing the observed variables that relate to each other and appear to measure the same thing (together they result in a score on the latent variable). So a factor analysis model would be drawn with arrows going from the factor to the observed variables, while a principal components analysis would be drawn with arrows going from the observed variables to the component.

More mathematically speaking, principal components analysis explains variance while factor analysis explains covariance (between items). In Winsteps, the Rasch program I use most frequently, the default dimension reduction technique is principal components analysis (also called PCA), and its goal is mainly to ensure that you aren't violating a key assumption of Rasch: that each item measures only one underlying latent construct. We refer to this as the assumption of unidimensionality. If the PCA shows the data violate this assumption, the PCA results can be used to divide items up into subscales, and then perform Rasch analysis on each subscale separately.

PCA output includes many important components, which I'll go through once we get the analysis. But two I want to highlight first are the eigenvalues and factor loadings. Eigenvalues are decompositions of variance, that help to uncover exactly how many factors are present in the data. You'll receive multiple eigenvalues in your analysis, which are contrasts: splitting up the items into the different components based on patterns of correlation. If the first eigenvalue is high and the rest are small (less than 1 or 2, depending on who you ask), that means there is only one component. You want the number of high eigenvalues to be less than the number of items in your measure. If the number of high eigenvalues is equal to the number of items, that means these items don't hang together and aren't measuring the same thing. Basically, this information tells you how many subscales appear to be in your data.

Next is factor loadings, which range from 0 to 1 (and can be positive or negative) and tell you how strongly an item relates to a specific factor or component. Loadings greater than 0.3 or 0.4 (again, based on who you ask) mean an item should be associated with that factor. For most measures, you only want an item to have a high loading on one factor. So you want each item to have a high loading (closer to 1 is better) on 1 factor and loadings close to 0 on the rest of the factors.

You can easily conduct PCA using the psych package. I was originally going to write today's post on the psych package, but it's huge and there's too much to cover. (Yes, I did just include "huge" and "package" in the same sentence on a stats blog.) There's a great website, maintained by the package developer, William Revelle, where you can learn about the many capabilities offered by psych. I frequently use the psych package to run quick descriptive statistics on a dataset (with the describe function). And I also used psych to demonstrate Cronbach's alpha way back at the beginning of this month (which feels like it was years ago instead of just a couple weeks). psych is a great general purpose package for psychological researchers with a heavy focus on psychometrics, so I'd definitely add it to your R packages if you haven't already done so.

So for the sake of simplicity and brevity, I'll focus today on the principal function in the psych package. To demonstrate, I'll use the Facebook dataset, since it contains multiple scales I can use with the principal function. (This isn't how you'd use PCA in practice - since these are developed scales with a known factor structure, confirmatory factor analysis is probably the best approach. But let's pretend for now that these are simply items created toward new scales and that we're looking for ways they might hang together.)

We'll start by installing (if necessary)/loading the psych package, as well as reading in our Facebook dataset.

install.packages("psych")
## Installing package into '/R/win-library/3.4'
## (as 'lib' is unspecified)
library(psych)
## Warning: package 'psych' was built under R version 3.4.4
Facebook<-read.delim("small_facebook_set.txt", header=TRUE)

Now let's dig into the principal function. You can quickly view what arguments a function allows by requesting args:

args(principal)
## function (r, nfactors = 1, residuals = FALSE, rotate = "varimax", 
##     n.obs = NA, covar = FALSE, scores = TRUE, missing = FALSE, 
##     impute = "median", oblique.scores = TRUE, method = "regression", 
##     ...) 
## NULL

r refers to the object you want to analyze - in our case, it will be a data frame, but you could also use a correlation matrix, as long as you also specify n.obs. You can request that the program extract a certain number of factors by setting nfactors. Residuals simply asks if you want the program to report residuals in your output.

The next argument, rotate, is a bit more complicated. There are multiple rotation methods available: "none", "varimax", "quartimax", "promax", "oblimin", "simplimax", and "cluster". But you're probably asking - what exactly is "rotation"? Rotation adds another step into the analysis to help understand and clarify the pattern of loadings. Basically, you can make one of two assumptions about the factors/components in your analysis: they are correlated (oblique) or they are uncorrelated (orthogonal). There are different rotation methods to use depending on which of these assumptions you make. You can learn more about rotation here. If you assume your factors are orthogonal, most would recommend using varimax, which is the default rotation method in the principal function. If you assume your factors are correlated, promax is often recommended. Some discourage rotation completely, which is why none is an option. We'll try all three for demonstration purposes.

Setting scores to TRUE requests the program to generate scale/subscale scores on the factor(s) identified. And missing plus impute is used when you have missing values and want the program to score results; it tells the program to impute missing values, with either "median" or "mean", when generating scores. method also relates to the component scores; with "regression", the default, scale/subscale scores are generated with a linear equation. Finally, olique.scores refers to the matrix (structural versus pattern) used in conducting the PCA; this is a more advanced concept that we won't get into now. You can leave this argument out at the moment. But maybe I should dig into this topic more in a future post or two.

We're now ready to try running a PCA with some of the Facebook data. Let's turn once again to our Ruminative Response Scale data. Remember that this measure can generate a total score, as well as scores on 3 subscales: Depression-Related Rumination, Brooding, and Reflecting. To make it easy to access just the RRS items, I'm going to create another data frame that copies over responses on these items. Then I'll run a PCA, using the default rotation method, on this data frame.

RRS<-Facebook[,3:24]
RRSpca<-principal(RRS)

Now I have an object called RRSpca that holds the results of this analysis. First, let's take a look at our eigenvalues:

RRSpca$values
##  [1] 8.8723501 1.6920860 1.1413928 1.1209452 1.0072739 0.8236229 0.7535618
##  [8] 0.6838558 0.6530697 0.6427205 0.5703730 0.5616363 0.4937120 0.4860600
## [15] 0.4218528 0.3830052 0.3388684 0.3185341 0.2863681 0.2675727 0.2468134
## [22] 0.2343256

Most of the variance is accounted for by the first contrast, which contains all of the items on a single component. This supports reporting a total score for the RRS. It doesn't support the presence of the 3 subscales, though. Let's take a look at the rest of our results:

RRSpca
## Principal Components Analysis
## Call: principal(r = RRS)
## Standardized loadings (pattern matrix) based upon correlation matrix
##        PC1   h2   u2 com
## Rum1  0.62 0.38 0.62   1
## Rum2  0.53 0.28 0.72   1
## Rum3  0.50 0.25 0.75   1
## Rum4  0.57 0.32 0.68   1
## Rum5  0.57 0.32 0.68   1
## Rum6  0.64 0.41 0.59   1
## Rum7  0.64 0.41 0.59   1
## Rum8  0.64 0.41 0.59   1
## Rum9  0.62 0.38 0.62   1
## Rum10 0.66 0.44 0.56   1
## Rum11 0.61 0.37 0.63   1
## Rum12 0.35 0.12 0.88   1
## Rum13 0.55 0.30 0.70   1
## Rum14 0.70 0.49 0.51   1
## Rum15 0.69 0.47 0.53   1
## Rum16 0.76 0.58 0.42   1
## Rum17 0.74 0.54 0.46   1
## Rum18 0.71 0.50 0.50   1
## Rum19 0.71 0.50 0.50   1
## Rum20 0.75 0.56 0.44   1
## Rum21 0.57 0.33 0.67   1
## Rum22 0.71 0.51 0.49   1
## 
##                 PC1
## SS loadings    8.87
## Proportion Var 0.40
## 
## Mean item complexity =  1
## Test of the hypothesis that 1 component is sufficient.
## 
## The root mean square of the residuals (RMSR) is  0.08 
##  with the empirical chi square  725.56  with prob <  3.2e-58 
## 
## Fit based upon off diagonal values = 0.96

All of the factor loadings, shown in the column PC1, are greater than 0.3. The lowest loading is 0.35 for item 12. I tend to use a cut-off of 0.4, so I might raise an eyebrow at this item, and if I were developing a scale, I might consider dropping this item. The column h2 is a measure of communalities, and u2 is uniqueness; you'll also notice they add up to 1. Communalities refers to shared variance with the other items, while uniqueness is variance not explained by the other items, but that could be explained by the latent variable as well as measurement error. The last column is complexity, which we'll ignore for now.

Near the bottom of the output, you'll see SS (sum of squares) loadings, which is equal to your first eigenvalue, as well as proportion var - this tells us that 40% of the variance in responses can be explained by the first latent variable. Finally, you'll see some familiar fit indices - RMSEA, chi-square, and fit based upon off diagnoal values (a goodness of fit statistic, with values closer to 1 indicating better fit).

Overall, these values support moderate to good fit. Since there's only 1 factor/component, rotation method doesn't really matter; remember, rotation refers to the correlations between factors or components, and we only have one. But let's try running these same data again, using the varimax rotation, and forcing the program to extract 3 components.

RRSpca_3<-principal(RRS, nfactors = 3)
RRSpca_3$values
##  [1] 8.8723501 1.6920860 1.1413928 1.1209452 1.0072739 0.8236229 0.7535618
##  [8] 0.6838558 0.6530697 0.6427205 0.5703730 0.5616363 0.4937120 0.4860600
## [15] 0.4218528 0.3830052 0.3388684 0.3185341 0.2863681 0.2675727 0.2468134
## [22] 0.2343256
RRSpca_3
## Principal Components Analysis
## Call: principal(r = RRS, nfactors = 3)
## Standardized loadings (pattern matrix) based upon correlation matrix
##         RC1  RC3   RC2   h2   u2 com
## Rum1   0.59 0.19  0.24 0.45 0.55 1.5
## Rum2   0.05 0.65  0.23 0.48 0.52 1.3
## Rum3   0.43 0.43 -0.09 0.38 0.62 2.1
## Rum4   0.24 0.73 -0.04 0.58 0.42 1.2
## Rum5   0.60 0.21  0.10 0.42 0.58 1.3
## Rum6   0.37 0.63  0.06 0.54 0.46 1.6
## Rum7   0.41 0.17  0.57 0.53 0.47 2.0
## Rum8   0.32 0.44  0.36 0.42 0.58 2.8
## Rum9   0.19 0.69  0.18 0.54 0.46 1.3
## Rum10  0.24 0.54  0.38 0.50 0.50 2.2
## Rum11  0.23 0.18  0.74 0.63 0.37 1.3
## Rum12 -0.02 0.04  0.72 0.52 0.48 1.0
## Rum13  0.58 0.17  0.14 0.39 0.61 1.3
## Rum14  0.29 0.69  0.21 0.61 0.39 1.5
## Rum15  0.70 0.24  0.18 0.58 0.42 1.4
## Rum16  0.54 0.47  0.27 0.59 0.41 2.5
## Rum17  0.70 0.15  0.40 0.67 0.33 1.7
## Rum18  0.69 0.25  0.23 0.59 0.41 1.5
## Rum19  0.57 0.47  0.13 0.56 0.44 2.1
## Rum20  0.44 0.33  0.56 0.61 0.39 2.6
## Rum21  0.27 0.10  0.71 0.59 0.41 1.3
## Rum22  0.43 0.41  0.40 0.51 0.49 3.0
## 
##                        RC1  RC3  RC2
## SS loadings           4.45 4.03 3.22
## Proportion Var        0.20 0.18 0.15
## Cumulative Var        0.20 0.39 0.53
## Proportion Explained  0.38 0.34 0.27
## Cumulative Proportion 0.38 0.73 1.00
## 
## Mean item complexity =  1.8
## Test of the hypothesis that 3 components are sufficient.
## 
## The root mean square of the residuals (RMSR) is  0.06 
##  with the empirical chi square  463.32  with prob <  1.9e-29 
## 
## Fit based upon off diagonal values = 0.97

I showed the eigenvalues once again, so you can see that they're the same. These are based on the actual variance in the data, and not the exact solution you're forcing on the data. Taking a look at the factor loadings, we see that certain items loaded highly on more than 1. In fact, this is when we look at complexity, which tells us how many factors an item loads on. Values close to 1 mean an item loads cleanly on one and only one factor. Values 2 or greater suggest an item is measuring two or more latent constructs simultaneously. Depending on the scale you're trying to create and how you plan to use it, this could be very problematic.

However, we do know that these subscales are correlated with each other. Let's see what happens when we use an oblique rotation instead.

RRSpca_3ob<-principal(RRS, nfactors = 3, rotate="promax")
RRSpca_3ob
## Principal Components Analysis
## Call: principal(r = RRS, nfactors = 3, rotate = "promax")
## Standardized loadings (pattern matrix) based upon correlation matrix
##         RC1   RC3   RC2   h2   u2 com
## Rum1   0.67 -0.06  0.08 0.45 0.55 1.0
## Rum2  -0.29  0.79  0.15 0.48 0.52 1.3
## Rum3   0.41  0.39 -0.30 0.38 0.62 2.8
## Rum4   0.00  0.84 -0.23 0.58 0.42 1.1
## Rum5   0.70 -0.01 -0.08 0.42 0.58 1.0
## Rum6   0.20  0.64 -0.13 0.54 0.46 1.3
## Rum7   0.36 -0.05  0.51 0.53 0.47 1.8
## Rum8   0.15  0.37  0.25 0.42 0.58 2.1
## Rum9  -0.09  0.78  0.04 0.54 0.46 1.0
## Rum10 -0.01  0.54  0.28 0.50 0.50 1.5
## Rum11  0.06  0.02  0.75 0.63 0.37 1.0
## Rum12 -0.21 -0.05  0.82 0.52 0.48 1.1
## Rum13  0.67 -0.06 -0.03 0.39 0.61 1.0
## Rum14  0.03  0.74  0.05 0.61 0.39 1.0
## Rum15  0.80 -0.03 -0.03 0.58 0.42 1.0
## Rum16  0.45  0.33  0.08 0.59 0.41 1.9
## Rum17  0.79 -0.18  0.23 0.67 0.33 1.3
## Rum18  0.77 -0.02  0.03 0.59 0.41 1.0
## Rum19  0.52  0.34 -0.09 0.56 0.44 1.8
## Rum20  0.31  0.15  0.46 0.61 0.39 2.0
## Rum21  0.16 -0.11  0.73 0.59 0.41 1.1
## Rum22  0.31  0.28  0.27 0.51 0.49 3.0
## 
##                        RC1  RC3  RC2
## SS loadings           4.76 4.02 2.93
## Proportion Var        0.22 0.18 0.13
## Cumulative Var        0.22 0.40 0.53
## Proportion Explained  0.41 0.34 0.25
## Cumulative Proportion 0.41 0.75 1.00
## 
##  With component correlations of 
##      RC1  RC3  RC2
## RC1 1.00 0.68 0.52
## RC3 0.68 1.00 0.46
## RC2 0.52 0.46 1.00
## 
## Mean item complexity =  1.5
## Test of the hypothesis that 3 components are sufficient.
## 
## The root mean square of the residuals (RMSR) is  0.06 
##  with the empirical chi square  463.32  with prob <  1.9e-29 
## 
## Fit based upon off diagonal values = 0.97

In some cases, this improved our solution, bringing complexity below 2. In others, such as for item 3, it made the problem worse. But using this rotation, we only have a few items we'd need to drop if we wanted to ensure a simple solution - one in which each item loads significantly onto only 1 factor. Just for fun, let's see what happens if we use no rotation.

RRSpca_3no<-principal(RRS, nfactors = 3, rotate="none")
RRSpca_3no
## Principal Components Analysis
## Call: principal(r = RRS, nfactors = 3, rotate = "none")
## Standardized loadings (pattern matrix) based upon correlation matrix
##        PC1   PC2   PC3   h2   u2 com
## Rum1  0.62  0.06 -0.26 0.45 0.55 1.4
## Rum2  0.53 -0.20  0.41 0.48 0.52 2.2
## Rum3  0.50 -0.35 -0.12 0.38 0.62 1.9
## Rum4  0.57 -0.47  0.21 0.58 0.42 2.2
## Rum5  0.57 -0.07 -0.30 0.42 0.58 1.6
## Rum6  0.64 -0.34  0.09 0.54 0.46 1.6
## Rum7  0.64  0.34 -0.01 0.53 0.47 1.5
## Rum8  0.64  0.02  0.13 0.42 0.58 1.1
## Rum9  0.62 -0.27  0.29 0.54 0.46 1.9
## Rum10 0.66 -0.02  0.25 0.50 0.50 1.3
## Rum11 0.61  0.48  0.19 0.63 0.37 2.1
## Rum12 0.35  0.55  0.30 0.52 0.48 2.3
## Rum13 0.55 -0.01 -0.29 0.39 0.61 1.5
## Rum14 0.70 -0.25  0.24 0.61 0.39 1.5
## Rum15 0.69 -0.03 -0.33 0.58 0.42 1.4
## Rum16 0.76 -0.09 -0.05 0.59 0.41 1.0
## Rum17 0.74  0.20 -0.30 0.67 0.33 1.5
## Rum18 0.71  0.01 -0.30 0.59 0.41 1.3
## Rum19 0.71 -0.20 -0.12 0.56 0.44 1.2
## Rum20 0.75  0.23  0.05 0.61 0.39 1.2
## Rum21 0.57  0.50  0.11 0.59 0.41 2.0
## Rum22 0.71  0.06  0.04 0.51 0.49 1.0
## 
##                        PC1  PC2  PC3
## SS loadings           8.87 1.69 1.14
## Proportion Var        0.40 0.08 0.05
## Cumulative Var        0.40 0.48 0.53
## Proportion Explained  0.76 0.14 0.10
## Cumulative Proportion 0.76 0.90 1.00
## 
## Mean item complexity =  1.6
## Test of the hypothesis that 3 components are sufficient.
## 
## The root mean square of the residuals (RMSR) is  0.06 
##  with the empirical chi square  463.32  with prob <  1.9e-29 
## 
## Fit based upon off diagonal values = 0.97

We still have items loading onto more than 1 factor, but not nearly as many as when we use varimax rotation. The promax rotation seems to be superior here, but using no rotation produces really similar results. Also, notice that our RMSEA and goodness of fit have improved for the 3 factor solution. But if this were my brand new measure, and these were my pilot data, based on the eigenvalues, I'd probably opt for the 1 factor solution.

Hope you enjoyed this post! I still prefer CFA for this kind of analysis, and in my current job, rarely even use the PCA results provided by the Rasch program - we tend to use our content validation study results as support for dimensionality - but I have used PCA to analyze some survey data we collected. Each analysis technique can be useful in certain ways and for certain situations.