Julia 如何使用for eachrow在数据帧上迭代时为列赋值

Julia 如何使用for eachrow在数据帧上迭代时为列赋值,julia,Julia,我有以下代码。它基本上迭代数据帧中的行,并尝试为列C赋值 我试图找到如何实现这一目标,但没有成功。我知道这个句子r.C=I*100是不正确的,哪一个是为每个迭代行的C列赋值的正确句子 请注意,这个问题是一个简化的示例,在我的实际代码中,我需要实际迭代每一行,因为计算要复杂得多 文件main2.jl: struct MyStruct a::Int32 b::Int32 c::String end df = DataFrame( A=Int[], B=Int[] ) pus

我有以下代码。它基本上迭代数据帧中的行,并尝试为列C赋值

我试图找到如何实现这一目标,但没有成功。我知道这个句子
r.C=I*100
是不正确的,哪一个是为每个迭代行的C列赋值的正确句子

请注意,这个问题是一个简化的示例,在我的实际代码中,我需要实际迭代每一行,因为计算要复杂得多

文件main2.jl

struct MyStruct
    a::Int32
    b::Int32
    c::String
end

df = DataFrame( A=Int[], B=Int[] )
push!(df, [1, 10])
push!(df, [2, 20])
push!(df, [3, 30])

insertcols!(df, 3, :C => Int)


println(df)

i = 1
for r in eachrow(df)
    global i
    r.C = i*100
    i = i + 1
end
我得到:

julia> include("main2.jl")
|     A |     B |        C |
| Int64 | Int64 | DataType |
|-------|-------|----------|
|     1 |    10 |    Int64 |
|     2 |    20 |    Int64 |
|     3 |    30 |    Int64 |
ERROR: LoadError: MethodError: Cannot `convert` an object of type Int64 to an object of type DataType
Closest candidates are:
  convert(::Type{S}, ::T<:(Union{CategoricalString{R}, CategoricalValue{T,R} where T} where R)) where {S, T<:(Union{CategoricalString{R}, CategoricalValue{T,R} where T} where R)} at /home/.../.julia/packages/CategoricalArrays/qcwgl/src/value.jl:91
  convert(::Type{T}, ::T) where T at essentials.jl:167
Stacktrace:
 [1] setindex!(::Array{DataType,1}, ::Int64, ::Int64) at ./array.jl:766
 [2] insert_single_entry!(::DataFrame, ::Int64, ::Int64, ::Int64) at /home/.../.julia/packages/DataFrames/yH0f6/src/dataframe/dataframe.jl:458
 [3] setindex! at /home/.../.julia/packages/DataFrames/yH0f6/src/dataframe/dataframe.jl:497 [inlined]
 [4] setindex! at /home/.../.julia/packages/DataFrames/yH0f6/src/dataframerow/dataframerow.jl:106 [inlined]
 [5] setproperty!(::DataFrameRow{DataFrame,DataFrames.Index}, ::Symbol, ::Int64) at /home/.../.julia/packages/DataFrames/yH0f6/src/dataframerow/dataframerow.jl:129
 [6] top-level scope at /usr/home/.../main2.jl:23
 [7] include at ./boot.jl:328 [inlined]
 [8] include_relative(::Module, ::String) at ./loading.jl:1094
 [9] include(::Module, ::String) at ./Base.jl:31
 [10] include(::String) at ./client.jl:431
 [11] top-level scope at REPL[1]:1
in expression starting at /usr/home/.../main2.jl:21
julia>include(“main2.jl”)
|A | B | C|
|Int64 | Int64 |数据类型|
|-------|-------|----------|
|1 | 10 | Int64|
|2 | 20 | Int64|
|3 | 30 | Int64|
错误:LoadError:MethodError:无法将Int64类型的对象“转换”为DataType类型的对象
最接近的候选人是:
convert(::Type{S},::T问题出在

插入工具!(df,3,:C=>Int)

在这里,您使用类型(Int)而不是Int值(如0)初始化:C列

插入工具!(df,3,:C=>0)


有效。

数据帧添加具有sentinel值的列的标准方法是:

df[!, :C] .= 0

<代码> INSERTCOLS!可以使用,但通常在您要在“代码>数据文件中间插入一列时使用(不作为最后一列,我的示例是什么)。

现在,您在问题末尾所写的循环可以表述为:

for (i, r) in enumerate(eachrow(df))
    r.C = i*100
end
我认为这是一种更典型的方法

最后,你可以简单地写下:

df.C = 100 .* axes(df, 1)
为了获得相同的效果。请注意,最后一条语句可能要复杂得多,如:

df.C = @. 100 * $axes(df, 1) + df.A + sin(df.B)
或者在这种情况下是等效的

df.C = 100 * axes(df, 1) + df.A + sin.(df.B)

(一般来说,当处理数据帧而不是循环时,您可以自由使用广播)

如果我想插入一个包含给定结构的空数组的新列,该怎么办?我尝试:
df[!,:C].=Vector{MyStruct}[]
但它不起作用,它说
“LoadError:DiensionMismatch(”无法广播阵列以匹配目标“)
您的语句试图将一个MyStruct放入C列的每一行中。您可以创建一个包含3个MyStruct的列表,这将非常适合,因为您有3行。编译器可以重复类似于0的整数,但它不知道如何创建默认MyStruct,以便在收到MyStruct的空数组时填充列。我想要的是一个空的MyStruct每行中的y MyStruct数组,而不是每行中的一个MyStruct。或者一个“未定义”的数组,以后可以通过MyStruct.Harder数组通过
为每个行中的r(df)
填充。创建一个伪结构,如m=MyStruct(0,0,”),然后df[!,:C]。=[m,m],[m]]应该可以。不过我想知道你是否不应该有更深层的数据帧结构。我认为一个标准的方法是
df.C=Vector{MyStruct}(unde,nrow(df))
。这是明确的(代码在6个月后很容易阅读)和快速的(也就是说,您不需要在需要之前花费时间/内存来分配任何内容)。您还可以编写例如
df[!,:C].=MyStruct.(df.A,df.B,“some_string”)
来一次性填充列(同样,在许多情况下,您可以使用广播而不是for循环)。谢谢,如果您想进一步说明正在添加的列是结构数组的情况,请参阅Bill回答中的注释(即,我打算在C列中添加可变长度的结构数组,我不知道是否可行)