ความเห็น: 1
การวิเคราะห์องค์ประกอบเชิงยืนยันด้วย sem package ใน R: ก้าวย่างทางเดิน ลืมเลือนคืนวัน ดั้นด้นไป
ทบทวน CFA (Confirmatory Factor Analysis) ด้วย R กันลืมนะครับ
ทฤษฏียกเอาไว้นะครับ
ใน R มี package สำหรับวิเคราะห์ CFA หลาย Package ด้วยกัน แต่ที่ผมเคยลองใช้ก็เป็น sem กับ lavaan ครับ package หลังสุดนี่ใช้งานง่ายหน่อยครับ แต่อาจจะติดตรงที่จำนวนดัชนีสำหรับ CFA นั้นมีน้อยกว่าอีก package หนึ่ง
Sem นี่ ใช้งานยากกว่านิดนึง แต่มีดัชนี CFA หลายตัวให้ดู
SEM = Structural Equation Modeling
ความยากของ SEM ก็คือการเขียนสมการโครงสร้างสำหรับเป็น input ให้ R นี่แหละครับ ซึ่งการเขียนสมการโครงสร้างก็ต้องเริ่มต้นจากการ path diagram ครับ เขียนสมการได้ต้องมี path diagram หรือตัวโครงสร้างตามทฤษฎี/ กรอบแนวคิดของเรานั่นเอง
ต้องเขียน path diagram ให้ได้ก่อน กำหนดว่า path ระหว่าง Latent variable (construct) กับ Observable variable (manifest variable) ภาษาไทยก็คงเป็นตัวแปรแฝงกับตัวแปรสังเกตได้ ทำนองนั้นครับ
ต้องเขียนเส้นทาง ว่าอันไหนเป็น direct effect indirect effect เป็น correlation, ….
จากนั้นนำเอาโครงสร้างที่เราเขียน (ต้องการทดสอบกับข้อมูล) มาแปลงให้เป็นภาษาของสมการโครงสร้างเพื่อเป็น input ให้กับ R นอกเหนือจากที่ต้องใส่ข้อมูลที่เก็บรวบรวมมาเป็น input อีกหนึ่งอย่าง
การเขียนสมการโครงสร้างนี่มีวิธีการเขียนอยู่หลายแบบ ซึ่งผมก็ไม่เคยเจอะไม่เคยเจอ เช่น LISREL , RAM1, RAM2, Bentler-Weeks, และ EzPath models
การแปลงสมการโครงสร้างเป็นภาษาที่ R เข้าใจ (ในที่นี้คือ package sem) นั้นเขียนเป็นภาษา ASCII ที่ชื่อว่า PATH1 (James H. Steiger)
R สามารถถอด code ของการเขียน model แบบ RAM ได้
ในที่นี้ก็ให้เข้าใจว่า RAM นั้นคืออะไร เป็นแบบไหนก็ช่างหัวมันเถอะ
วิธีการนำเข้า model หรือจะเรียกว่า path diagram สู่ environment ของ R นั้นทำได้ผ่านหลายฟังก์ชันด้วยกัน แต่ที่ง่ายที่สุดก็คือการนำเข้าผ่านฟังก์ชัน cfa()
ฟังก์ชัน cfa() ใน sem นะครับ
ตัวอย่างต่อไปนี้เป็นตัวอย่างที่นำมาจากงานวิจัยของ Holzinger และ Swineford (1939) เป็นข้อมูลส่วนหนึ่ง (73 records)
Holzinger และ Swineford ทำการทดสอบเด็ก (ผู้หญิง) ด้วย seven test (different aspects of educational ability) ซึ่งประกอบไปด้วย
- Visual perception
- Cube identification
- lozenge identification
- Word meanings
- sentence structure
- paragraph understanding
นำเข้าข้อมูลตัวอย่าง
> t7 <- read.table("t7.dat", header=T)
> head(t7)
visperc cubes lozenges paragrap sentence wordmean
1 33 22 17 8 17 10
2 30 25 20 10 23 18
3 36 33 36 17 25 41
4 28 25 9 10 18 11
5 30 25 11 11 21 8
6 20 25 6 9 21 16
ในที่นี้เราจะทำการทดสอบยืนยันว่า t7 เป็นการวัด 2 กลุ่ม/ domain (2 latent variables) คือ visual perception (vp) กับ reading (rd)
Path diagram คือ (ในที่นี้เราจะละสัญลักษณ์ต่าง ๆ เช่น lamda, phi, error, … ไว้ไม่เขียนใน diagram)
ฟังก์ชัน cfa() นี้สามารถใส่ input ได้ 2 แบบคือ อนโดยตรงที่ Rconsole หรือเรียกสมการจากแฟ้มข้อมูล ในที่นี้จะใช้การ input ข้อมูลผ่าน Rconsole
> ct7 <- cfa(reference.indicators=FALSE, covs=NULL)
1: vp: visperc, cubes, lozenges
2: rd: paragrap, sentence, wordmean
3:
Read 2 items
NOTE: adding 6 variances to the model
> ct7
Path Parameter StartValue
1 vp -> visperc lam[visperc:vp]
2 vp -> cubes lam[cubes:vp]
3 vp -> lozenges lam[lozenges:vp]
4 rd -> paragrap lam[paragrap:rd]
5 rd -> sentence lam[sentence:rd]
6 rd -> wordmean lam[wordmean:rd]
7 vp <-> vp <fixed> 1
8 rd <-> rd <fixed> 1
9 visperc <-> visperc V[visperc]
10 cubes <-> cube V[cubes]
11 lozenges <-> lozenges V[lozenges]
12 paragrap <-> paragrap V[paragrap]
13 sentence <-> sentence V[sentence]
14 wordmean <-> wordmean V[wordmean]
ที่เราเห็นผลลัพธ์ข้างต้นนั่นคือการแปลงจาก input ของฟังก์ชัน cfa() ให้เป็นภาษา PATH1
จากนั้นสร้าง correlation matrix ของข้อมูล
> cot7 <- cor(t7)
> cot7
visperc cubes lozenges paragrap sentence wordmean
visperc 1.0000000 0.4828862 0.4916630 0.3430168 0.3667612 0.2297377
cubes 0.4828862 1.0000000 0.4924264 0.2106977 0.1786094 0.1838991
lozenges 0.4916630 0.4924264 1.0000000 0.3258026 0.3354078 0.3689271
paragrap 0.3430168 0.2106977 0.3258026 1.0000000 0.7243611 0.7430226
sentence 0.3667612 0.1786094 0.3354078 0.7243611 1.0000000 0.6955315
wordmean 0.2297377 0.1838991 0.3689271 0.7430226 0.6955315 1.0000000
เมื่อทุกอย่างพร้อมก็สั่ง fit สมการ โดยที่ N= จำนวนข้อมูลทั้งหมด และ S= correlation matrix ของข้อมูล (ระหว่างตัวแปร)
> semt7 <- sem(ct7, N=73,S=cot7)
จากนั้นสั่งให้แสดงผลลัพธ์โดยแสดงค่าดัชนีต่าง ๆ
> summary(semt7,conf.level=.95,fit.indices=c("GFI", "AGFI", "RMSEA", "NFI", "NNFI","CFI", "RNI", "IFI", "SRMR"))
Model Chisquare = 19.86044 Df = 9 Pr(>Chisq) = 0.01879349
Goodness-of-fit index = 0.9219684
Adjusted goodness-of-fit index = 0.8179262
RMSEA index = 0.1294602 95% CI: (0.02492434, 0.2204861)
Bentler-Bonett NFI = 0.8942005
Tucker-Lewis NNFI = 0.8952005
Bentler CFI = 0.9371203
Bentler RNI = 0.9371203
Bollen IFI = 0.9392313
SRMR = 0.1914631
Normalized Residuals
Min. 1st Qu. Median Mean 3rd Qu. Max.
-0.0000011 -0.0000001 0.7578000 1.1990000 2.7650000 3.1300000
R-square for Endogenous Variables
visperc cubes lozenges paragrap sentence wordmean
0.4821 0.4836 0.5014 0.7738 0.6781 0.7135
Parameter Estimates
Estimate Std Error z value Pr(>|z|)
lam[visperc:vp] 0.6943612 0.12659520 5.484893 4.137188e-08 visperc <--- vp
lam[cubes:vp] 0.6954395 0.12662144 5.492273 3.967935e-08 cubes <--- vp
lam[lozenges:vp] 0.7080795 0.12693163 5.578432 2.426961e-08 lozenges <--- vp
lam[paragrap:rd] 0.8796707 0.09856879 8.924434 4.479843e-19 paragrap <--- rd
lam[sentence:rd] 0.8234458 0.10115440 8.140485 3.936984e-16 sentence <--- rd
lam[wordmean:rd] 0.8446600 0.10020665 8.429181 3.480937e-17 wordmean <--- rd
V[visperc] 0.5178625 0.13427138 3.856834 1.148649e-04 visperc <--> visperc
V[cubes] 0.5163638 0.13435632 3.843242 1.214197e-04 cubes <--> cubes
V[lozenges] 0.4986234 0.13545010 3.681233 2.321084e-04 lozenges <--> lozenges
V[paragrap] 0.2261796 0.07167599 3.155583 1.601775e-03 paragrap <--> paragrap
V[sentence] 0.3219371 0.07571344 4.252047 2.118252e-05 sentence <--> sentence
V[wordmean] 0.2865496 0.07375643 3.885080 1.022960e-04 wordmean <--> wordmean
Iterations = 23
จากการทดสอบสมการด้วย Chi-square test ให้ผลการทดสอบ significant หรือค่า Chi-square = 19.80644 degree of freedom เท่ากับ 9 แสดงให้เห็นว่า โมเดลโครงสร้างตามทฤษฎีหรือกรอบแนวคิดที่เรากำหนดขึ้นใน diagram ยังไม่ fit หรือยังมีความแตกต่างจากโมเดลการวัด (ข้อมูล) อยู่
เราอาจจะปรับโมเดลโครงสร้างของเราใหม่ ซึ่งมี 2 แนวคิดคือ เพิ่มเส้นความสัมพันธ์ในโมเดลกับลดเส้นความสัมพันธ์ในโมเดล
ข้อแนะนำจากผู้เชี่ยวชาญคือการเพิ่มเส้นความสัมพันธ์ในโมเดล แต่จะเพิ่มเส้นที่ใดดี (ระหว่าง ? กับ ?๗
ใน package sem มีฟังก์ชันที่ใช้ตรวจสอบว่า หากเราเพิ่ม/ กำหนดความสัมพันธ์ขึ้นในโมเดลแล้ว จะทำให้สามารถลดค่า chi-square ลงได้เท่าไหร่ เราเลือกเพิ่มเส้นความสัมพันธ์ให้กับตัวแปรที่สามารถลดค่า chi-square ลงได้มากที่สุด
ฟังก์ชันใน sem ที่ว่าคือ modInduces() หรือ Model Induces นั่นเอง หรือความสัมพันธ์ที่เพิ่มเข้าไป ความสัมพันธ์แบบไหน/ ระหว่างอะไร ที่ส่งผลต่อการเปลี่ยนแปลงของสมการ
> modIndices(semt7)
5 largest modification indices, A matrix (regression coefficients):
vp<-rd rd<-vp rd<-lozenges vp<-sentence vp<-paragrap
10.761443 10.761443 10.278320 9.451144 9.415826
5 largest modification indices, P matrix (variances/covariances):
rd<->vp rd<->lozenges wordmean<->lozenges wordmean<->visperc sentence<->visperc
10.761443 3.935540 3.208525 2.760979 2.694762
จากผลลัพธ์ของ modInduces() ทำให้เราทราบว่า ถ้าเราเพิ่มความสัมพันธ์ระหว่างตัวแปร vc กับ rd เข้าไปจะทำให้ค่า chi-square ลดลงมา 10.761 ซึ่งตัวแปร vc และ rd นั้นเป็นตัวแปรแฝง (latent variable)
เราจะเลือกเส้นความสัมพันธ์ระหว่าง vc กับ rd ในรูปแบบใด?
ความสัมพันธ์ทางเดียวกับความสัมพันธ์ 2 ทาง
ทางเดียว (สัญญลักษณ์ลูกศรทางเดียว) เช่น rd ส่งผลต่อ vc หรือ vc ส่งผลต่อ rd (ส่งผลให้ค่า chi-sqaure ลดลงเท่ากัน)
สองทาง (สัญญลักษณ์ลูกศร 2 ทาง) หรือในอีกนัยยะหนึ่งคือ vc กับ rd ส่งผลซึ่งกันและกัน หรือมีความสัมพันธ์กันเอง
ผู้เชี่ยวชาญให้ความเห็นว่า ควรเลือกเส้นความสัมพันธ์ที่เป็นทางเดียว แต่จะเลือกตัวแปรไหนไปตัวแปรไหนนั้นคงขึ้นกับความหมายของตัวแปรแต่ละตัว
ในที่นี้เพิ่มเส้นความสัมพันธ์ระหว่าง vp กับ rd โดยที่ให้ vp ไป rd (อันนี้สมมติเอาดื้อ ๆ ว่า vp ส่งผลต่อ rd หรือเห็นช่วยให้อ่านดีขึ้น)
เราปรับโมเดลใหม่ ในที่นี้ผมจะใช้การใส่โมเดลใหม่ทับโมเดลเดิม โดยเพิ่มบรรทัดที่เป็นความสัมพันธ์ระหว่าง vp กับ rd เพิ่มเข้าไปอีกบรรทัด ใช้การป้อนข้อมูลผ่านทาง Rconsole เช่นเดิมครับ
> ct7 <- cfa(reference.indicators=FALSE, covs=NULL)
1: vp: visperc, cubes, lozenges
2: rd: paragrap, sentence, wordmean
3: rd: vp:
4:
Read 3 items
NOTE: adding 6 variances to the model
> ct7
Path Parameter StartValue
1 vp -> visperc lam[visperc:vp]
2 vp -> cubes lam[cubes:vp]
3 vp -> lozenges lam[lozenges:vp]
4 rd -> paragrap lam[paragrap:rd]
5 rd -> sentence lam[sentence:rd]
6 rd -> wordmean lam[wordmean:rd]
7 rd -> vp lam[vp:rd]
8 vp <-> vp <fixed> 1
9 rd <-> rd <fixed> 1
10 visperc <-> visperc V[visperc]
11 cubes <-> cubes V[cubes]
12 lozenges <-> lozenges V[lozenges]
13 paragrap <-> paragrap V[paragrap]
14 sentence <-> sentence V[sentence]
15 wordmean <-> wordmean V[wordmean]
คราวนี้มา fit โมเดลอีกครั้ง (พร้อมทั้งสั่งแสดงผลลัพธ์)
> semt7 <- sem(ct7, N=73,S=cot7)
> summary(semt7,conf.level=.95,fit.indices=c("GFI", "AGFI", "RMSEA", "NFI", "NNFI","CFI", "RNI", "IFI", "SRMR"))
Model Chisquare = 7.852894 Df = 8 Pr(>Chisq) = 0.4479704
Goodness-of-fit index = 0.9658616
Adjusted goodness-of-fit index = 0.9103867
RMSEA index = 0 95% CI: (NA, 0.1522889)
Bentler-Bonett NFI = 0.9581665
Tucker-Lewis NNFI = 1.001597
Bentler CFI = 1
Bentler RNI = 1.000852
Bollen IFI = 1.000819
SRMR = 0.04293757
Normalized Residuals
Min. 1st Qu. Median Mean 3rd Qu. Max.
-0.695100 -0.193800 0.000001 -0.021430 0.180000 0.683500
R-square for Endogenous Variables
vp visperc cubes lozenges paragrap sentence wordmean
0.2372 0.4940 0.4275 0.5419 0.7736 0.6838 0.7081
Parameter Estimates
Estimate Std Error z value Pr(>|z|)
lam[visperc:vp] 0.6138345 0.11234527 5.463821 4.659926e-08 visperc <--- vp
lam[cubes:vp] 0.5710648 0.11168135 5.113340 3.165111e-07 cubes <--- vp
lam[lozenges:vp] 0.6429527 0.11340596 5.669479 1.432322e-08 lozenges <--- vp
lam[paragrap:rd] 0.8795392 0.09804371 8.970889 2.941304e-19 paragrap <--- rd
lam[sentence:rd] 0.8269340 0.10068013 8.213478 2.148724e-16 sentence <--- rd
lam[wordmean:rd] 0.8414863 0.09996723 8.417621 3.842058e-17 wordmean <--- rd
lam[vp:rd] 0.5576151 0.17756559 3.140333 1.687557e-03 vp <--- rd
V[visperc] 0.5060492 0.12689285 3.988004 6.663150e-05 visperc <--> visperc
V[cubes] 0.5724844 0.12749524 4.490241 7.114262e-06 cubes <--> cubes
V[lozenges] 0.4580750 0.12784742 3.582982 3.396938e-04 lozenges <--> lozenges
V[paragrap] 0.2264106 0.06938893 3.262921 1.102702e-03 paragrap <--> paragrap
V[sentence] 0.3161800 0.07417707 4.262503 2.021500e-05 sentence <--> sentence
V[wordmean] 0.2919008 0.07253485 4.024283 5.714914e-05 wordmean <--> wordmean
Iterations = 27
เริ่ดไหมครับ
แถมท้ายด้วย path diagram ที่สร้างจาก R
> pathDiagram(semt7, hat=TRUE,parameters=round(coef(semt7),3),style = "ram", node.colors = c("lightgreen", "yellow"))
ข้อสังเกต:
การกำหนดเครื่องหมายลูกศรใน diagram นั้นเราจะเห็นว่า ลูกศรพุ่งออกจากตัวแปรแฝง (latent variable) ไปยังตัวแปรสังเกตได้ (Observable variable) ทั้งนี้เป็นความหมายในนัยยะของปัจจัย (factor) แต่หากเรากำหนดให้ลูกศรพุ่งในทิศทางกลับกันนั่นคือ ลูกศรพุ่งออกจากตัวแปรสังเกตได้ (Observable variable) ไปยังตัวแปรแฝง (latent variable) จะเป็นความหมายในนัยยะขององค์ประกอบ (component)
อิอิอิ
เราเอง
เพลง: Hotter Than Hell
ศิลปิน: Kiss
บันทึกอื่นๆ
- เก่ากว่า « ขณะที่กีต้าร์ของฉันร่ำไห้เบา ๆ -...
- ใหม่กว่า » R & Diagram: ก้าวย่างทางเดิน ลืม...
30 พฤศจิกายน 2561 17:03
#108283
Thank for your writting! I have read through some similar topics! However, your post has given me a very special impression, unlike other posts. I hope you continue to have valuable articles like this or more to share with everyone! vex