这是我的代码:
carats <- pull(diamonds %>% distinct(carat) %>% arrange(carat))
get_price_by_category <- function(dataset, x, y) {
print(c(x, typeof(x)))
dataset %>% filter(carat == x) %>% print()
}
carats %>% walk(get_price_by_category, dataset = diamonds, y= "price")
当我运行它时,我得到以下结果:
[1] "0.2" "double"
# A tibble: 0 x 10
# … with 10 variables: carat <dbl>, cut <ord>, color <ord>, clarity <ord>,
# depth <dbl>, table <dbl>, price <int>, x <dbl>, y <dbl>, z <dbl>
[1] "0.21" "double"
# A tibble: 0 x 10
# … with 10 variables: carat <dbl>, cut <ord>, color <ord>, clarity <ord>,
# depth <dbl>, table <dbl>, price <int>, x <dbl>, y <dbl>, z <dbl>
[1] "0.22" "double"
# A tibble: 0 x 10
# … with 10 variables: carat <dbl>, cut <ord>, color <ord>, clarity <ord>,
# depth <dbl>, table <dbl>, price <int>, x <dbl>, y <dbl>, z <dbl>
[1] "0.23" "double"
# A tibble: 0 x 10
# … with 10 variables: carat <dbl>, cut <ord>, color <ord>, clarity <ord>,
# depth <dbl>, table <dbl>, price <int>, x <dbl>, y <dbl>, z <dbl>
...
因此,很明显,我的函数识别正在传递的值,并且变量类型等效于它所过滤的列的类型。但是,同样明显的是,它没有在过滤器(克拉== x)函数中根据需要处理它。
如果我通过将 walk() 更改为 for() 循环并显式传递克拉的值来更改代码:
carats <- pull(diamonds %>% distinct(carat) %>% arrange(carat))
get_price_by_category <- function(dataset, x, y) {
print(c(x, typeof(x)))
dataset %>% filter(carat == x) %>% print()
}
for (c in carats) {
get_price_by_category(diamonds, c, y= "price")
}
结果是一样的。
但是,如果我离开 for() 循环,但将函数中的代码更改为引用 c 而不是 x(即使我在参数列表中将其保留为 x),我也会得到想要的结果:
carats <- pull(diamonds %>% distinct(carat) %>% arrange(carat))
get_price_by_category <- function(dataset, x, y) {
print(c(c, typeof(c)))
dataset %>% filter(carat == c) %>% print()
}
for (c in carats) {
get_price_by_category(diamonds, c, y= "price")
}
结果:
[1] "0.2" "double"
# A tibble: 12 x 10
carat cut color clarity depth table price x y z
<dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
1 0.2 Premium E SI2 60.2 62 345 3.79 3.75 2.27
2 0.2 Premium E VS2 59.8 62 367 3.79 3.77 2.26
3 0.2 Premium E VS2 59 60 367 3.81 3.78 2.24
4 0.2 Premium E VS2 61.1 59 367 3.81 3.78 2.32
5 0.2 Premium E VS2 59.7 62 367 3.84 3.8 2.28
6 0.2 Ideal E VS2 59.7 55 367 3.86 3.84 2.3
7 0.2 Premium F VS2 62.6 59 367 3.73 3.71 2.33
8 0.2 Ideal D VS2 61.5 57 367 3.81 3.77 2.33
9 0.2 Very Good E VS2 63.4 59 367 3.74 3.71 2.36
10 0.2 Ideal E VS2 62.2 57 367 3.76 3.73 2.33
11 0.2 Premium D VS2 62.3 60 367 3.73 3.68 2.31
12 0.2 Premium D VS2 61.7 60 367 3.77 3.72 2.31
[1] "0.21" "double"
# A tibble: 9 x 10
carat cut color clarity depth table price x y z
<dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl>
1 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31
2 0.21 Very Good E VS2 63.2 54 386 3.82 3.78 2.4
3 0.21 Premium E VS2 60.5 59 386 3.87 3.83 2.33
4 0.21 Premium E VS2 59.6 56 386 3.93 3.89 2.33
5 0.21 Premium D VS2 61.6 59 386 3.82 3.78 2.34
6 0.21 Premium D VS2 60.6 60 386 3.85 3.81 2.32
7 0.21 Premium D VS2 59.1 62 386 3.89 3.86 2.29
8 0.21 Premium D VS2 58.3 59 386 3.96 3.93 2.3
9 0.21 Premium E SI2 61.9 56 394 3.84 3.82 2.37
...
因此,我可以在参数列表中将其保留为 x,并且只要在实际函数代码中将其引用为 c,我就可以仍然获得所需的结果,这一事实让我意识到我的调用中的值不知何故没有像我期望的那样传递给我的函数。但是我不知道为什么这不起作用,或者我需要做什么才能让它工作。
这里有两个问题,当你看到问题2时,我认为你应该真正看看问题1,这样你就不会被另一个错误咬伤。
不幸的是,在数字计算机上使用浮点进行相等测试存在根本缺陷(IEEE-754,R FAQ 7.31)。匹配浮点值的唯一保证是用容差(不等式测试)查看"周围",例如
abs(carat-0.2) < 1e-8
。(你可以侥幸逃脱一些比较,但你不会真正知道它什么时候会咬你,直到一些奇怪的事情发生,你深入挖掘。为此,您可能应该了解数据本身,以便正确告知您选择的1e-8
。x
被视为dataset$x
,而不是函数参数...尝试使用不在数据集中的参数名称。get_price_by_category <- function(dataset, a, b, tol = 1e-8) { print(c(x, typeof(x))) dataset %>% filter(abs(carat - a) < tol) %>% print() } carats %>% head(n=2) %>% walk(get_price_by_category, dataset = diamonds, b = "price") # [1] "0.2" "double" # # A tibble: 12 x 10 # carat cut color clarity depth table price x y z # <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl> # 1 0.2 Premium E SI2 60.2 62 345 3.79 3.75 2.27 # 2 0.2 Premium E VS2 59.8 62 367 3.79 3.77 2.26 # 3 0.2 Premium E VS2 59 60 367 3.81 3.78 2.24 # 4 0.2 Premium E VS2 61.1 59 367 3.81 3.78 2.32 # 5 0.2 Premium E VS2 59.7 62 367 3.84 3.8 2.28 # 6 0.2 Ideal E VS2 59.7 55 367 3.86 3.84 2.3 # 7 0.2 Premium F VS2 62.6 59 367 3.73 3.71 2.33 # 8 0.2 Ideal D VS2 61.5 57 367 3.81 3.77 2.33 # 9 0.2 Very Good E VS2 63.4 59 367 3.74 3.71 2.36 # 10 0.2 Ideal E VS2 62.2 57 367 3.76 3.73 2.33 # 11 0.2 Premium D VS2 62.3 60 367 3.73 3.68 2.31 # 12 0.2 Premium D VS2 61.7 60 367 3.77 3.72 2.31 # [1] "0.2" "double" # # A tibble: 9 x 10 # carat cut color clarity depth table price x y z # <dbl> <ord> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl> # 1 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31 # 2 0.21 Very Good E VS2 63.2 54 386 3.82 3.78 2.4 # 3 0.21 Premium E VS2 60.5 59 386 3.87 3.83 2.33 # 4 0.21 Premium E VS2 59.6 56 386 3.93 3.89 2.33 # 5 0.21 Premium D VS2 61.6 59 386 3.82 3.78 2.34 # 6 0.21 Premium D VS2 60.6 60 386 3.85 3.81 2.32 # 7 0.21 Premium D VS2 59.1 62 386 3.89 3.86 2.29 # 8 0.21 Premium D VS2 58.3 59 386 3.96 3.93 2.3 # 9 0.21 Premium E SI2 61.9 56 394 3.84 3.82 2.37
注:注:我再说一遍:tol
的选择对于这个函数的逻辑准确性至关重要。如果您正在处理的单位通常在 1 或 1000 中,有效数字为 8 或更少,那么1e-8
就可以了。如果您正在处理高精度数字,则可能需要更接近.Machine$double.eps
(在我的 64 位机器上,这是2.22e-16
,有关此变量组件的详细信息,请参阅?.Machine
)。我没有理由不默认,但这就是为什么我说"选择 1e-8 是正确的通知">——只有你知道你的数据,如果没有超过 1/1000 的实际差异,那么你可以使用tol=1e-3
。