R:将数据框中的分数转换为小数
R: converting fractions into decimals in a data frame
我正在尝试将以分数形式存储为字符的数字数据框转换为以小数形式存储的数字。 (还有一些整数,也存储为 char。)我想保留数据框的当前结构,即我不想要列表。
示例数据框(注意:真实数据框的所有元素都是字符,这里是一个因素,但我不知道如何复制带有字符的数据框):
a <- c("1","1/2","2")
b <- c("5/2","3","7/2")
c <- c("4","9/2","5")
df <- data.frame(a,b,c)
我试过了df[] <- apply(df,1, function(x) eval(parse(text=x)))
。这会正确计算数字,但仅限于最后一列,并用它填充数据框。
结果:
a b c
1 4 4.5 5
2 4 4.5 5
3 4 4.5 5
我也尝试了 df[] <- lapply(df, function(x) eval(parse(text=x)))
,结果如下(我不知道为什么):
a b c
1 3 3 2
2 3 3 2
3 3 3 2
想要的结果:
a b c
1 1 2.5 4
2 0.5 3 4.5
3 2 3.5 5
非常感谢!
您可能正在寻找:
df[] <- apply(df, c(1, 2), function(x) eval(parse(text = x)))
df
a b c
1 1.0 2.5 4.0
2 0.5 3.0 4.5
3 2.0 3.5 5.0
eval(parse(text = x))
一次计算一个表达式,因此您需要 运行 一个单元一个单元地计算。
编辑:如果无法评估某些数据框元素,您可以通过在函数内添加 ifelse 语句来解决这个问题:
df[] <- apply(df, c(1, 2), function(x) if(x %in% skip){NA} else {eval(parse(text = x))})
其中 skip 是不应计算的元素向量。
首先,你应该防止你的角色变成data.frame()
中的因素
df <- data.frame(a, b, c, stringsAsFactors = F)
然后你可以在你的 lapply
中包裹一个简单的 sapply/lapply
来实现你想要的。
sapply(X = df, FUN = function(v) {
sapply(X = v,
FUN = function(w) eval(parse(text=w)))
}
)
旁注
如果您向 eval
提供一个不正确的表达式,例如 expression(1, 1/2, 2)
,计算结果为最后一个值。这解释了 4 4.5 5
输出。正确的 expression(c(1, 1/2, 2))
评估为预期的答案。
代码lapply(df, function(x) eval(parse(text=x)))
returns一个3 3 2
因为sapply(data.frame(a,b,c), as.numeric)
returns:
a b c
[1,] 1 2 1
[2,] 2 1 3
[3,] 3 3 2
这些数字对应于 levels()
个因子,您通过这些因子存储分数。
对于那些寻找单行代码的人:您可以使用 DOSE 包中的 parse_ratio
将字符分数强制转换为数字。
library(DOSE)
b <- c("5/2","3","7/2")
parse_ratio(b)
[1] 2.5 1.0 3.5
我正在尝试将以分数形式存储为字符的数字数据框转换为以小数形式存储的数字。 (还有一些整数,也存储为 char。)我想保留数据框的当前结构,即我不想要列表。
示例数据框(注意:真实数据框的所有元素都是字符,这里是一个因素,但我不知道如何复制带有字符的数据框):
a <- c("1","1/2","2")
b <- c("5/2","3","7/2")
c <- c("4","9/2","5")
df <- data.frame(a,b,c)
我试过了df[] <- apply(df,1, function(x) eval(parse(text=x)))
。这会正确计算数字,但仅限于最后一列,并用它填充数据框。
结果:
a b c
1 4 4.5 5
2 4 4.5 5
3 4 4.5 5
我也尝试了 df[] <- lapply(df, function(x) eval(parse(text=x)))
,结果如下(我不知道为什么):
a b c
1 3 3 2
2 3 3 2
3 3 3 2
想要的结果:
a b c
1 1 2.5 4
2 0.5 3 4.5
3 2 3.5 5
非常感谢!
您可能正在寻找:
df[] <- apply(df, c(1, 2), function(x) eval(parse(text = x)))
df
a b c
1 1.0 2.5 4.0
2 0.5 3.0 4.5
3 2.0 3.5 5.0
eval(parse(text = x))
一次计算一个表达式,因此您需要 运行 一个单元一个单元地计算。
编辑:如果无法评估某些数据框元素,您可以通过在函数内添加 ifelse 语句来解决这个问题:
df[] <- apply(df, c(1, 2), function(x) if(x %in% skip){NA} else {eval(parse(text = x))})
其中 skip 是不应计算的元素向量。
首先,你应该防止你的角色变成
中的因素data.frame()
df <- data.frame(a, b, c, stringsAsFactors = F)
然后你可以在你的
lapply
中包裹一个简单的sapply/lapply
来实现你想要的。sapply(X = df, FUN = function(v) { sapply(X = v, FUN = function(w) eval(parse(text=w))) } )
旁注
如果您向
eval
提供一个不正确的表达式,例如expression(1, 1/2, 2)
,计算结果为最后一个值。这解释了4 4.5 5
输出。正确的expression(c(1, 1/2, 2))
评估为预期的答案。代码
lapply(df, function(x) eval(parse(text=x)))
returns一个3 3 2
因为sapply(data.frame(a,b,c), as.numeric)
returns:a b c [1,] 1 2 1 [2,] 2 1 3 [3,] 3 3 2
这些数字对应于
levels()
个因子,您通过这些因子存储分数。
对于那些寻找单行代码的人:您可以使用 DOSE 包中的 parse_ratio
将字符分数强制转换为数字。
library(DOSE)
b <- c("5/2","3","7/2")
parse_ratio(b)
[1] 2.5 1.0 3.5