使用tidyverse(dplyr)规范化混合数字/非数字数据帧中的列?

使用tidyverse(dplyr)规范化混合数字/非数字数据帧中的列?,r,dplyr,tidyverse,tidyeval,R,Dplyr,Tidyverse,Tidyeval,我经常需要规范化数据帧中混合了数字列和非数字列的列。有时我知道数字列的名称,有时不知道 我尝试过我认为非常合乎逻辑的整洁评估方法。大多数都不起作用。我只找到了一个 为了更好地理解tidy评估,我可以解释一下为什么以下选项有效或无效吗 库(tidyverse) df=data.frame( A=运行IF(10,1,10), B=运行IF(10,1,10), C=代表(0,10), D=字母[1:10] ) df #>A、B、C、D #>1.2.15711.4343510 A #>27.746638

我经常需要规范化数据帧中混合了数字列和非数字列的列。有时我知道数字列的名称,有时不知道

我尝试过我认为非常合乎逻辑的整洁评估方法。大多数都不起作用。我只找到了一个

为了更好地理解tidy评估,我可以解释一下为什么以下选项有效或无效吗

库(tidyverse)
df=data.frame(
A=运行IF(10,1,10),
B=运行IF(10,1,10),
C=代表(0,10),
D=字母[1:10]
)
df
#>A、B、C、D
#>1.2.15711.4343510 A
#>27.746638 6.987983 0 B
#>37.861337 1.528145 0摄氏度
#>4 8.657990 4.101441 0 D
#>5 8.307844 5.809815 0 E
#>6 1.376084 9.202047 0华氏度
#>7.197999 5.532681 0克
#>8 1.878676 1.012917 0小时
#>9 2.231955 4.572273 0 I
#>10 4.340488 2.640728 0 J
打印(“对列进行规格化,但无法处理0列”)
#>[1]“不规范列,但无法处理0的列”
test=df%>%mutate\u如果(是数字,~./和()
测试%>%如果(是数值)%%>%colSums()则选择
#>A、B、C
#>11楠
打印(“与上述内容基本相同,但尝试处理0列,但不起作用”)
#>[1]“实际上与上面相同,但尝试处理0列,但不起作用”
test=df%>%mutate_if(is.numeric,~ifelse(sum(.)>0,./sum(.)0))
测试%>%如果(是数值)%%>%colSums()则选择
#>A、B、C
#> 0.4167949 0.3349536 0.0000000
打印(“对列进行规格化,但无法处理0列”)
#>[1]“不规范列,但无法处理0的列”
test=df%>%mutate_if(is.numeric,function(x)x/sum(x))
测试%>%如果(是数值)%%>%colSums()则选择
#>A、B、C
#>11楠
打印(“与上述内容基本相同,但尝试处理0列,但不起作用”)
#>[1]“实际上与上面相同,但尝试处理0列,但不起作用”
test=df%>%mutate_if(is.numeric,function(x)ifelse(sum(x)>0,x/sum(x),0))
测试%>%如果(是数值)%%>%colSums()则选择
#>A、B、C
#> 0.4167949 0.3349536 0.0000000
打印(“奇怪的错误,我不明白”)
#>[1]“奇怪的错误我不明白”
test=df%>%mutate_if(is.numeric,~apply(,2,函数(x)x/sum(x)))
#>应用(,2,函数(x)x/sum(x))中出错:dim(x)必须具有正长度
打印(“这确实有效!为什么?”)
#>[1]“这确实有效!为什么?”
test=df%>%mutate_if(is.numeric,函数(x)if(sum(x)>0)x/sum(x))
测试%>%如果(是数值)%%>%colSums()则选择
#>A B
#> 1 1
由(v0.3.0)于2019-10-29创建

编辑 Ack!刚刚注意到一个大问题 在最后一个示例中,即“起作用”,0列被删除。我完全不明白这一点。我想保留该列,只是不想将其正常化

test=df%>%mutate_if(is.numeric,function(x)if(sum(x)>0)x/sum(x))
>试验
#A、B、D
#1 0.15571120 0.12033237 A
#2 0.10561824 0.11198394 B
#3 0.06041408 0.12068372 C
#4 0.16785724 0.06241538 D
#5 0.03112945 0.02559354 E
#6 0.02791520 0.06363215 F
#7 0.17132200 0.16625761克
#8 0.06641540 0.14038458小时
#9 0.04015548 0.12420858 I
#10 0.17346171 0.06450813 J
编辑2 我想我需要包括
其他

test=df%>%mutate_if(is.numeric,function(x)if(sum(x)>0){x/sum(x)}else{0})
>试验
#A、B、C、D
#1 0.15571120 0.12033237 0 A
#2 0.10561824 0.11198394 0 B
#30.06041408 0.12068372 0摄氏度
#4 0.16785724 0.06241538 0 D
#5 0.03112945 0.02559354 0 E
#6 0.02791520 0.06363215 0 F
#7 0.17132200 0.16625761 0克
#8 0.06641540 0.14038458 0小时
#9 0.04015548 0.12420858 0 I
#10 0.17346171 0.06450813 0 J
数字列=
df%>%
如果(是数值)%>%,请选择
colnames()
test=df%>%mutate_at(数值_列,函数(x)if(sum(x)>0)x/sum(x))
>试验
#A、B、C、D
#1 0.15571120 0.12033237 0 A
#2 0.10561824 0.11198394 0 B
#30.06041408 0.12068372 0摄氏度
#4 0.16785724 0.06241538 0 D
#5 0.03112945 0.02559354 0 E
#6 0.02791520 0.06363215 0 F
#7 0.17132200 0.16625761 0克
#8 0.06641540 0.14038458 0小时
#9 0.04015548 0.12420858 0 I
#10 0.17346171 0.06450813 0 J
第一个问题 您可以通过指定
na.rm=T
来处理问题,这样您就不会保留
na
。 它们的出现是因为除以0。 第二种语法也是一样的,第二种语法也一样
mutate_如果
对每个数字列应用所需的操作,那么对于第三个数字列,由于0,它返回Nan

第二个问题 ifelse返回一个与test形状相同的值,因此在您的情况下,因为您选中了'sum(x)>0',所以只返回第一个值。见:

第三个问题 在这里,这是一个棘手的问题,如果“按向量应用”并且您想使用“下一步应用”,则需要对_进行变异,但您的对象是一个向量,并且“应用”仅适用于像
矩阵
数据这样的对象。frame
至少有两列

一个好答案 实际上,这是一种正确的语法,因为
if
不需要返回特定大小的对象

但是,您也可以使用
ifelse
,但是如果至少有一个元素与0不同,那么向量条件的正值之和实际上不是nul

test = df %>% mutate_if(is.numeric, function(x){ifelse(x > 0, x/sum(x), rep(0, length(x)))})
test %>%  select_if(is.numeric) %>% colSums()
我希望它能帮助您理解出现错误时发生的情况。解决方案不是唯一的

编辑1: 原因是:只有当总和严格大于0时,才能返回某些内容。如果没有,则必须指定要执行的操作。比如说:

test = df %>% mutate_if(is.numeric, function(x) if(sum(x)>0){x/sum(x)}else{0})

@雷米·库劳德(Rémi Coulaud)已经很好地解释了为什么事情会起作用/不起作用。现在,可以(根据@42-)的评论更新)另一种处理此问题的方法:

然后:

df %>% 
 mutate_if(~ is.numeric(.) && sum(.) != 0, ~ ./sum(.)) %>%
 select_if(is.numeric) %>%
 colSums()

A B C 
1 1 0 
@雷米——谢谢你!我还没有完全了解这些,但我会阅读文档并进行一些实验。然而,即使使用“工作”解决方案,我也意识到了一个大问题。你能看一下吗
test = df %>% mutate_if(is.numeric, function(x) if(sum(x)>0) x/sum(x))
test %>% select_if(is.numeric) %>% colSums()
test = df %>% mutate_if(is.numeric, function(x){ifelse(x > 0, x/sum(x), rep(0, length(x)))})
test %>%  select_if(is.numeric) %>% colSums()
test = df %>% mutate_if(is.numeric, function(x) if(sum(x)>0){x/sum(x)}else{0})
df %>% 
 mutate_if(~ is.numeric(.) && sum(.) != 0, ~ ./sum(.))

            A          B C D
1  0.15735803 0.12131787 0 A
2  0.08098114 0.10229536 0 B
3  0.06108911 0.09802935 0 C
4  0.13152492 0.15719599 0 D
5  0.10684839 0.10477812 0 E
6  0.14204157 0.10385447 0 F
7  0.09731823 0.11015997 0 G
8  0.15532621 0.10458007 0 H
9  0.02579446 0.05748756 0 I
10 0.04171793 0.04030124 0 J
df %>% 
 mutate_if(~ is.numeric(.) && sum(.) != 0, ~ ./sum(.)) %>%
 select_if(is.numeric) %>%
 colSums()

A B C 
1 1 0