社会科学研究经常会遇到“超多变量”的情况——多量表、多维度、多题项,以及复杂的正反计分题……如何更高效地计算量表总分?如何更简洁地进行反向计分?传统的统计工具(Excel、SPSS等)虽然也能解决这些问题,但在超多变量的情况下会比较繁琐。相反,R语言以其扩展包的强大功能和代码的极简风格,狂甩传统软件几十条街。今天我们就来掌握如何使用R语言优雅地计算超多变量(包括计算总分、计算平均值、缺失值处理、数值计数、重新编码、反向计分等)。

本文目录:

  1. 温故——传统软件的解决办法概览
  2. 知新——R语言和data.table包
  3. 进阶——自编R函数优雅计算多变量(附相关代码)

1 / 传统软件的解决办法概览

我们以经典的10题Rosenberg自尊量表(RSES)为例,这是一个4点Likert量表(1-4),其中有5题反向计分(第3、5、8、9、10题)。

如果用Excel来计算其总分或平均分,大家应该已经很熟悉了,可以分别用SUMAVERAGE函数:比如从A列~J列是RSES的10道题,那么在K2格输入“=AVERAGE(A2,B2,5-C2,D2,5-E2,F2,G2,5-H2,5-I2,5-J2)”,然后双击K2格右下角的黑色小十字,就自动填充算出了所有人的量表平均分。如果没有反向计分题,会简单很多,可以直接“=AVERAGE(A2:J2)”。想必这是大多数读者再熟悉不过的方法。

如果换做是SPSS,可能稍微复杂一点,比如原始变量名是RSES1、RSES2……RSES10,那么计算平均分可以先RECODE其中5道反向计分题并生成新变量再COMPUTE,也可以不RECODE直接COMPUTE(当然如果要计算信度,还是得先RECODE生成新变量):

COMPUTE RSES=MEAN(RSES1, RSES2, 5-RSES3, RSES4, 5-RSES5, RSES6, RSES7, 5-RSES8, 5-RSES9, 5-RSES10).
EXECUTE.

同样,在不涉及反向计分的情况下,SPSS的语句也能通过“to”(大小写不敏感)得到简化(但变量需要按顺序排好):

COMPUTE X=MEAN(X1 to X50).
EXECUTE.

如此看来,传统方法似乎还比较方便,所以这可能也是目前很多同学或老师不愿意学习使用R的原因:原来的软件已经够用、学编程需要花费比较多的成本、不想写代码、畏惧写代码……或者,学着学着就“从入门到放弃”了……

其实可以理解,毕竟我们有时候不太想跳出舒适区。

然而,随着变量增多,Excel和SPSS就会变得越来越不方便、越来越繁琐。

2 / R语言和data.table包

R语言会极大提高数据分析的效率,并且可以做几乎所有的统计分析。

自从两年前入坑R,我在一次次分析数据的过程中逐渐体会到R语言的美妙之处,无论是数据处理的简洁程度、统计功能的强大程度,还是作图的美观程度。虽说一个心理学研究者并不必要掌握太多编程语言(不可否认,问题比方法更重要,想法比技术更重要),但R绝对是一个巨大的宝库,经常会给我们很多惊喜,长远来看也会节省我们很多时间和精力。

在数据预处理方面,data.table作为data.frame的继承和升级版,不仅在处理大容量数据的时候速度更快,而且在拥有强大功能的同时代码设计却非常优雅简洁。官方速查手册请参考data.table (cheat sheet)。

data.table简介

data.table的基本使用方式是“data[i, j, by]”(i为行,j为列,by为分组变量)。下面是一些例子:

require(data.table)
data=data.table(x=rep(1:2, each=3), y=1:6, z=6:1)
#    x y z
# 1: 1 1 6
# 2: 1 2 5
# 3: 1 3 4
# 4: 2 4 3
# 5: 2 5 2
# 6: 2 6 1# 筛选符合条件的行/个案
data[x==1 & y>1]
#    x y z
# 1: 1 2 5
# 2: 1 3 4# 筛选特定的列/变量
data[, c("y", "z")]
data[, .(y, z)]
#    y z
# 1: 1 6
# 2: 2 5
# 3: 3 4
# 4: 4 3
# 5: 5 2
# 6: 6 1# 同时筛选行和列
data[y %between% c(2, 4), "z"]
#    z
# 1: 5
# 2: 4
# 3: 3# 分组汇总
data[order(x), .(TotalN=.N, Ymean=mean(y), Zsd=sd(z), Zmax=max(z)), by=x]
#    x TotalN Ymean Zsd Zmax
# 1: 1      3     2   1    6
# 2: 2      3     5   1    3# 变量计算(“原地更新”,无需赋值给新变量)
data[, sum:=x+y+z]
#    x y z sum
# 1: 1 1 6   8
# 2: 1 2 5   8
# 3: 1 3 4   8
# 4: 2 4 3   9
# 5: 2 5 2   9
# 6: 2 6 1   9# 多变量同时计算(“:=”实则为data.table的一个特殊函数)
data[,":="(sum_xy=x+y,`y*z`=y*z)]
#    x y z sum sum_xy y*z
# 1: 1 1 6   8      2   6
# 2: 1 2 5   8      3  10
# 3: 1 3 4   8      4  12
# 4: 2 4 3   9      6  12
# 5: 2 5 2   9      7  10
# 6: 2 6 1   9      8   6# 数据匹配合并(即merge)
d1=data.table(x=letters[1:4], y=1:4)
#    x y
# 1: a 1
# 2: b 2
# 3: c 3
# 4: d 4
d2=data.table(x=letters[3:1], z=1:3)
#    x z
# 1: c 1
# 2: b 2
# 3: a 3
d2[d1, on="x"]  # 保留d1所有case
#    x  z y
# 1: a  3 1
# 2: b  2 2
# 3: c  1 3
# 4: d NA 4
d1[d2, on="x"]  # 保留d2所有case
#    x y z
# 1: c 3 1
# 2: b 2 2
# 3: a 1 3

通过上面这些简单的例子,大家对data.table应该已经有了基本的感受——非常简洁。事实上,如果要在data.frame实现相同的功能,还需要用到许多其他的函数和包(例如which、aggregate、merge,多变量计算则需要用到dplyr包的mutate等等),而在data.table里面,一切都变得非常优雅。

然而,优雅才刚刚开始。

3 / 自编R函数优雅计算多变量

虽然data.table提供了“:=”函数使得多变量计算容易很多,但现实情况往往比较复杂,尤其是本文开头所说的“超多变量”情况。颇为遗憾的是,data.table本身并没有提供特别有效的函数来“优雅地”进行“超多变量”的计算。

我们不妨先创建一个案例数据,用来模拟纷繁复杂的现实情况,这里我刻意把“x2”和“x4”的位置倒了过来,并且加了几个缺失值NA:

d=data.table(x1=1:5, x4=c(2,2,5,4,5), x3=c(3,2,NA,NA,5), x2=c(4,4,NA,4,5), x5=c(5,4,3,4,5))
#    x1 x4 x3 x2 x5
# 1:  1  2  3  4  5
# 2:  2  2  2  4  4
# 3:  3  5 NA NA  3
# 4:  4  4 NA  4  4
# 5:  5  5  5  5  5# 如果要计算x1-x5的平均值:
# (以下均为错误代码!)
d[,":="(X=mean(x1, x2, x3, x4, x5))]  # 报错
d[,":="(X=mean(c(x1, x2, x3, x4, x5)))]  # 依然不对,返回值都是NA
d[,":="(X=mean(c(x1, x2, x3, x4, x5), na.rm=TRUE))]  # 还是不对,返回值都是同一个数字
d[,":="(X=(x1+x2+x3+x4+x5)/5)]  # 回到了最笨的办法,但缺失值依然无法处理

可以看到,如果我们想计算x1-x5的平均值,想想容易,真正实现起来却处处碰壁。其实要想实现简便的变量计算,需要用到很多特别的函数,比如mapply、eval,有的地方还需要用到正则表达式。

但不用担心,我已经针对几个常用的变量计算需求编好了相应的R函数。由于具体思路比较复杂,这里不详细展示源代码,大家可以从我的GitHub下载这些函数的源代码并调用(BruceFunctions.R)。

# 或者在线调用BruceFunctions.R
source("https://raw.githubusercontent.com/psychbruce/stats/master/BruceFunctions.R")

自编函数包括:

COUNT:统计每个被试的不同变量(题目)中某个值出现的个数SUM:简便计算多个变量(题目)的总分MEAN:简便计算多个变量(题目)的平均分STD:简便计算多个变量(题目)的标准差CONSEC:统计多个变量(题目)中连续相同数字出现最多的个数……

主要的参数包括:

data:原数据var & item:需计算的变量及其序号(同时定义),例如var="RSES", item=1:10;如果变量的原始顺序是乱序,则变量会以1-10的顺序重新排列;此为推荐用法,可省略参数名vars:直接规定使用哪些变量,例如vars=c("x1", "x2");不可省略该参数名varrange:原数据中某段范围的变量(原始顺序),例如varrange="x1:x5";不可省略该参数名
(以上三种变量界定方式只需选择其中一种即可,当然函数在实际运行时会把不同情况统一转换为vars)rev:反向计分题有哪些,可以是单个数字(与item参数的顺序对应),可以是具体的变量名,也可以是数字/变量名组成的向量likert:如果有反向计分题,则需要同时定义Likert是几点量表,可以是c(1, 7)的形式,也可以是1:7的形式na.rm:是否跳过缺失值,默认为TRUE(适用大多数情况),一般不用再做设置

下面是具体用法:

d[,":="(n_na=COUNT(d, "x", 1:5, value=NA),  # 统计x1-x5中缺失值的个数n_2=COUNT(d, "x", 1:5, value=2),  # 统计2的个数sum=SUM(d, "x", 1:5),  # 计算x1-x5的总分(缺失值跳过)mean1=MEAN(d, "x", 1:5),  # 计算x1-x5的平均分(缺失值跳过)mean2=MEAN(d, vars=c("x1", "x4")),  # 只计算x1和x4的平均分mean3=MEAN(d, varrange=c("x1", "x2")),  # 计算从x1到x2的平均分(实际有4个变量)mean4=MEAN(d, varrange="x1:x2", rev="x2", likert=1:5),  # 同上,但规定x2为反向计分题sd=STD(d, "x", 1:5, rev=c(2, 5), likert=1:5),  # 计算x1-x5的标准差,规定x2和x5为反向计分题cons1=CONSEC(d, "x", 1:5),  # 统计x1-x5连续相同数字出现最多的个数(变量按照1-5重新排列)cons2=CONSEC(d, varrange="x1:x5"))]  # 同上,但以变量原始顺序排列#    x1 x4 x3 x2 x5 n_na n_2 sum    mean1 mean2 mean3    mean4       sd cons1 cons2
# 1:  1  2  3  4  5    0   1  15 3.000000   1.5   2.5 2.000000 0.836660     0     0
# 2:  2  2  2  4  4    0   3  14 2.800000   2.0   2.5 2.000000 0.000000     2     3
# 3:  3  5 NA NA  3    2   0  11 3.666667   4.0   4.0 4.000000 1.154701     0     0
# 4:  4  4 NA  4  4    1   0  16 4.000000   4.0   4.0 3.333333 1.154701     2     2
# 5:  5  5  5  5  5    0   0  25 5.000000   5.0   5.0 4.000000 2.190890     5     4

另外,还有两个函数是在已有包的基础上进行的简单扩展(所谓“站在巨人的肩膀上”):

RECODE:变量转换/重新赋值,功能同SPSS的RECODE;该函数是直接调用了car包的recode函数

# RECODE用法示例
data[, BirthGroup:=RECODE(BirthYear, "lo:1989=1; 1990:1999=2; 2000:2009=3; 2010:hi=4; else=NA")]

Alpha:更方便地计算内部一致性信度,不需要对反向计分题额外生成新变量;该函数是调用了jmv包的reliability函数(jmv其实是jamovi软件的程序包),并做了必要的参数设置和参数扩展
(输出结果为三线表,指标包括5个——量表平均分、量表标准差、量表α系数、校正后的题总相关 [即item-rest correlation]、该题如果删除后的量表α系数,以及会智能输出一些Note)

最后仍然以RSES自尊量表为例,演示上述函数的用法:

# 计算平均分(数据“原地更新”)
data[, ":="(RSES=MEAN(data, "RSES", 1:10, rev=c(3, 5, 8, 9, 10), likert=1:4))]# 计算Cronbach's α系数
Alpha(data, "RSES", 1:10, rev=c(3, 5, 8, 9, 10))

Alpha函数输出结果样例(基于jamovi的jmv包)

结语

面对“多变量计算”问题,虽然Excel和SPSS也能解决,但局限较多、过程繁琐。而基于data.table和自编函数,我们既可以很方便地用少量代码计算量表总分、量表平均分,也能在不生成新变量的情况下直接进行反向计分的处理和量表信度的计算,而且基本上所有的单个功能都只需要短短一行代码就能搞定。大道至简。

再啰(ān)嗦(lì)几句

  • 用R千万别用R本身(我一般只用R本身当计算器),RStudio才是写代码必需的IDE(IDE = 集成开发环境)
  • jamovi作为一款基于R的新兴统计软件,具有比SPSS更简洁美观的界面设计,同时又拥有更强大丰富的统计功能,未来几年应该会大范围取代SPSS,和R一起占领统计市场(jamovi的一个新出的module甚至已经能做多重中介和有调节的中介了)
  • 简单数据用jamovi、复杂数据用R——可以说是一种新的标配
  • 到底有多好,谁用谁知道!

r语言清除变量_如何优雅地计算多变量 | R语言进阶相关推荐

  1. R 回归 虚拟变量na_如何优雅地计算多变量

    作者:包寒吴霜 中科院心理所硕士在读(名字/人格/社会/文化心理学) 知乎:https://www.zhihu.com/people/psychbruce 社会科学研究经常会遇到"超多变量& ...

  2. c++如何把字符串转为变量名_如何优雅地计算多变量

    作者:包寒吴霜 中科院心理所硕士在读(名字/人格/社会/文化心理学) 知乎:https://www.zhihu.com/people/psychbruce 社会科学研究经常会遇到"超多变量& ...

  3. r语言清除变量_R语言(1)初识与数据结构

    点击上方蓝字,记得关注我们! a picture is worth a thousand words! 一,R语言简介 1,R语言的发展 上世纪90年代初,新西兰奥克兰大学 Ross Ihaka 和 ...

  4. go语言csv包_玩转数据处理120题R语言版本

    点击上方"早起Python",关注并星标公众号 和我一起玩Python 本文为玩转数据处理120题|R语言版本 习题|刘早起,解答|陈熹 大家好,本文为R语言数据处理120题系列完 ...

  5. java语言程序设计视频_[VIP视频]【A0152】Java语言程序设计进阶高级进阶视频教程 网易云课堂 百度网盘 云盘...

    Java语言程序设计进阶-云课堂' S0 c5 z4 C* S: n: K/ D ├─第1周 类和对象 9 i5 N/ j$ I9 d9 z9 t# [# U: D│      1.1 用类制造对象. ...

  6. linux系统如何切换语言环境变量,Linux系统中如何修改某用户语言环境变量

    在所管理的服务器上,有的可以在终端里面输入汉字,有的不行,会显示乱码.比较其相对应的环境变量.发现关于语言的环境变量不一样.在网上搜索了大量的资料,没有找到解决的方法.看了鸟哥书中相关的部分才找到解决 ...

  7. 下列选项中属于c语言合法变量名的是,计算机二级考试C语言模拟练习

    C语言是一个有结构化程序设计.具有变量作用域以及递归功能的过程式语言.下面给大家整理了计算机二级考试C语言模拟练习,一起来看看吧! 计算机二级考试C语言模拟练习 1). 关于C语言的变量,以下叙述中错 ...

  8. c语言读png图片非隔行扫描,北京大学计算概论C语言经典课件Lecture4信息显示与多媒体技术.ppt...

    北京大学计算概论C语言经典课件Lecture4信息显示与多媒体技术 * * * * 控制在10页 * 有人说科学的作用是安抚,艺术的作用是颠覆.科学家严谨的思维和艺术家非凡的创造力.灵活的表现力之间看 ...

  9. r语言清除变量_R语言:结构方程模型、潜变量分析

    原文链接: R语言:结构方程模型.潜变量分析​tecdat.cn 结构方程模型入门 介绍 对于熟悉线性回归拟合结构方程模型的分析师来说,在R环境中,拟合结构方程模型涉及学习新的建模语法,新的绘图语法以 ...

最新文章

  1. Listview 的顶部动态广告位的实现
  2. 你以为 CSS 只是个简单的布局?装逼指南了解一下
  3. 南通儒通软件上机面试题
  4. python模拟登陆 验证码el_8-python模拟登入(无验证码)
  5. Python+django网页设计入门(4):用户登录与登录验证
  6. YOLODet最新算法的目标检测开发套件,优化到部署
  7. C# await和async
  8. Kubernetes 小白学习笔记(8)--kubernetes的基础概念
  9. 射频测试系统软件,射频测试可以不懂测试仪器?“仪器程控系统”软件助你极大提升测试效率...
  10. 微信小程序 input隐藏和不可操作的设置
  11. Modbus通信协议
  12. html5 模板 知乎,Discuz贴吧知乎超级v2ex UTF(x520_v2ex)_Discuz模板_Discuz应用中心
  13. MySQL 规范数据库设计
  14. Home Assistant设备追踪之ping检测和nmap检测
  15. 3.3 泰勒(Taylor)公式和麦克劳林(Maclaurin)公式
  16. 3dsmax UVW展开,然后在 BodyPaint 3D 中进行绘制
  17. 常微分方程初值问题数值解法[完整公式](Python)
  18. 近期一个称重设备微信端开发前端知识点,及使用插件遇到的常见问题
  19. Codeforces #839A: Arya and Bran 题解
  20. 蠕虫病毒疯狂传播如何预防

热门文章

  1. HttpURLConnection, Android访问网络,实用demo
  2. 小程序 mpvue input 文本控制
  3. python 类和对象 有必要学吗_类与对象-python学习19
  4. 会移动的文字(Marquee)
  5. android特殊代码,安卓手机输入这些特殊代码,电池状态查得清清楚楚!
  6. bootstrap 学习网址
  7. 面向接口编程的优点_为什么我们要面向接口编程
  8. dubbo使用nacos作为注册中心
  9. cpc卡内计费信息异常包括_今日头条信息流广告投放效果好吗?信息流广告计费方式怎么收费?...
  10. java ReentrantLock 使用