考虑到这一点:
dict = Dict(("y" => ":x / 2"))
df = DataFrame(x = [1, 2, 3, 4])
df
4×1 DataFrame
│ Row │ x │
│ │ Int64 │
├─────┼───────┤
│ 1 │ 1 │
│ 2 │ 2 │
│ 3 │ 3 │
│ 4 │ 4 │
我想制作这个:
4×2 DataFrame
│ Row │ x │ y │
│ │ Int64 │ Float64 │
├─────┼───────┼─────────┤
│ 1 │ 1 │ 0.5 │
│ 2 │ 2 │ 1.0 │
│ 3 │ 3 │ 1.5 │
│ 4 │ 4 │ 2.0 │
这似乎是一个完美的应用程序,可以使用 DataFramesMeta 的 @with 或 @eachrow,但我尚未能够在存在 :x 的环境中按预期评估我的表达式。
基本上,我想能够迭代字典中的 (k, v) 对,并为每个 Symbol(k) 创建一个新列,其相应值为 eval(Meta.parse(v)) 或类似的内容,其中求值发生在诸如 :x 之类的 Symbols 在评估时存在的情况下。
我没指望这会起作用,而且它确实没有。
[df[Symbol(k)] = eval(Meta.parse(v)) for (k, v) in dict]
ERROR: MethodError: no method matching /(::Symbol, ::Int64)
但这说明了问题:我需要在包含这些符号的环境中计算这些表达式。
但是,将其移到@with
内部并不能解决问题:
using DataFramesMeta
@with(df, [eval(Meta.parse(v)) for (k, v) in dict])
ERROR: MethodError: no method matching /(::Symbol, ::Int64)
使用@eachrow
会出现相同的失败情况:
using DataFramesMeta
@eachrow df begin
for (k, v) in dict
@newcol tmp::Vector{Float32}
tmp = eval(Meta.parse(v))
end
end
ERROR: MethodError: no method matching /(::Symbol, ::Int64)
我猜我对于
DataFramesMeta
如何在DataFrame中创建环境的关键要素理解不清晰。我也不一定非得使用DataFramesMeta
,因为任何合理简洁的选项都可以,因为我可以将其封装在一个包函数中。注:我控制要解析为表达式的字符串的格式,但我想避免复杂性,例如在字符串中指定DataFrame对象的名称或广播每个操作。我希望初始字符串中的表达式语法对于非Julia程序员来说相对清晰。
更新:我在这个问题的评论中尝试了所有三个解决方案,它们有一个问题:它们在函数内部不起作用。
dict = Dict(("y" => ":x / 2"))
data = DataFrame(x = [1, 2, 3, 4])
function transform_from_dict(df, dict)
new = eval(Meta.parse("@transform(df, " * join(join.(collect(dict), " = "), ", ") * ")"))
return new
end
transform_from_dict(data, dict)
ERROR: UndefVarError: df not defined
或者:
function transform_from_dict!(df, dict)
[df[!, Symbol(k)] = eval(:(@with(df, $(Meta.parse(v))))) for (k, v) in dict]
return nothing
end
transform_from_dict!(data, dict)
ERROR: UndefVarError: df not defined
[df[!,Symbol(k)] = eval(DataFramesMeta.with_helper(df, Meta.parse(v))) for (k, v) in dict]
- 张实唯[df[!,Symbol(k)] = eval(:(@with(df, $(Meta.parse(v))))) for (k, v) in dict]
。这两个都有些棘手。关键是不要直接eval
v
,而是让DataFramesMeta
用它的魔力来评估它。 - 张实唯eval(Meta.parse("@transform(df, " * join(join.(collect(dict), " = "), ", ") * ")"))
。 - Bogumił Kamińskieval
在模块的全局作用域中被评估。DataFramesMeta.jl不会创建eval
环境,但其宏在编译时而非运行时解析。 - Bogumił Kamińskiglobal new
,并在函数(内部)的开头也添加global new
。这是 Python 中的一个通用技巧,适用于任何需要在运行时读取并随时间增长的对象。请参阅 https://thispointer.com/python-how-to-use-global-variables-in-a-function/。也许它也适用于 Julia。然后,df 可以在任何列表 / 字典推导式中增长。未经测试:也许它也可以与 eval() + Meta.parse() 结合使用。顺便说一下:我没有看到这是 Julia 而不是 Python,请将这个想法转移到 Julia。 - questionto42