tidyverse中pivot_longer()为何需过滤value?有无不操作value的写法
问题解答
行数变为原数据4倍的原因
这是pivot_longer()的默认运行逻辑导致的:
- 你在
cols参数中指定了A、B、C、D共4个列执行宽转长操作 - 该函数不会自动识别哑变量的业务含义,默认行为是:对你指定的每一个待转置列,都为原始数据的每一行生成一条独立的长格式记录,记录内容包括「当前列名(存入你指定的treatment列)」和「该列在当前行的单元格取值」
原始数据共5行,每行会对应生成4条转置记录,总条数为5*4=20行,刚好是原数据行数的4倍,和你运行得到的结果完全匹配。
为什么需要filter(value == 1)语句
你数据中的A、B、C、D列是典型的独热编码(哑变量)结构:每一行原始数据只会在其实际所属处理组的列上取值为1,其余不匹配的处理组列都取值为0。pivot_longer()转置完成后,会默认把所有待转置列的单元格取值存入名为value的列,你必须筛选value == 1的行,才能保留每个观测实际对应的处理组记录,删掉剩下3条value=0的无意义占位行,最后移除value列就能得到符合tidy原则的结果。
不提及value列的实现方式
不存在完全不依赖0/1取值判断的实现方案:A/B/C/D列的单元格值是判断每行对应哪个treatment的唯一依据,不管你写不写出value这个列名,都需要基于这些取值筛选有效行——value只是转置函数给存取值的列设置的默认列名,你完全可以调整写法,让代码里不出现value字符串,比如使用tidyr新版本支持的values_filter参数,在转置过程中直接完成筛选,不需要后续单独写过滤和删列语句:
df %>% pivot_longer( cols = c(A, B, C, D), names_to = "treatment", values_to = NULL, values_filter = ~.x == 1 )
运行上述代码可以直接得到你预期的结果,全程不需要提到value列,也不需要额外写filter和select语句,但本质逻辑还是基于单元格取值筛选有效记录,和你原来的写法没有差异。
内容的提问来源于stack exchange,提问作者John Thomas
相关产品推荐
相关产品推荐

