#julia
#джулия
Вопрос:
Я довольно новичок в Джулии, поэтому прошу прощения, если это очень простой вопрос. Из R я привык выполнять базовые операции с несколькими столбцами фрейма данных одновременно. Я попытался сделать это в Julia следующим образом:
У меня есть два фрейма данных, давайте назовем их data_1 и data_2:
using DataFrames
data_1 = DataFrame(rand(4,6))
data_2 = DataFrame(zeros(4,6))
И теперь я хочу заполнить data_2 как разницу определенных строк из data_1, например:
data_2[1,:] = data_1[1,:] - data_1[2,:]
но это приводит к ошибке. Итак, как я могу изменить этот подход, чтобы успешно вычесть несколько столбцов строк фрейма данных?
Большое вам спасибо!
Ответ №1:
К сожалению, эта конкретная задача немного сложна, поскольку мы пытаемся сохранить согласованность с базой Julia.
Вот способы сделать это:
Вариант 1
Используйте итерацию:
julia> data_1 = DataFrame(reshape(1:24, 4, 6))
4×6 DataFrame
│ Row │ x1 │ x2 │ x3 │ x4 │ x5 │ x6 │
│ │ Int64 │ Int64 │ Int64 │ Int64 │ Int64 │ Int64 │
├─────┼───────┼───────┼───────┼───────┼───────┼───────┤
│ 1 │ 1 │ 5 │ 9 │ 13 │ 17 │ 21 │
│ 2 │ 2 │ 6 │ 10 │ 14 │ 18 │ 22 │
│ 3 │ 3 │ 7 │ 11 │ 15 │ 19 │ 23 │
│ 4 │ 4 │ 8 │ 12 │ 16 │ 20 │ 24 │
julia> data_2 = DataFrame(zeros(4,6))
4×6 DataFrame
│ Row │ x1 │ x2 │ x3 │ x4 │ x5 │ x6 │
│ │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │
├─────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ 1 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
│ 2 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
│ 3 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
│ 4 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
julia> foreach(i -> data_2[1,i] = data_1[1, i] - data_1[2, i], axes(data_1, 2))
julia> data_2
4×6 DataFrame
│ Row │ x1 │ x2 │ x3 │ x4 │ x5 │ x6 │
│ │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │
├─────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ 1 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │
│ 2 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
│ 3 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
│ 4 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
Вариант 2
Используйте широковещательную передачу фреймов данных:
julia> data_1 = DataFrame(reshape(1:24, 4, 6))
4×6 DataFrame
│ Row │ x1 │ x2 │ x3 │ x4 │ x5 │ x6 │
│ │ Int64 │ Int64 │ Int64 │ Int64 │ Int64 │ Int64 │
├─────┼───────┼───────┼───────┼───────┼───────┼───────┤
│ 1 │ 1 │ 5 │ 9 │ 13 │ 17 │ 21 │
│ 2 │ 2 │ 6 │ 10 │ 14 │ 18 │ 22 │
│ 3 │ 3 │ 7 │ 11 │ 15 │ 19 │ 23 │
│ 4 │ 4 │ 8 │ 12 │ 16 │ 20 │ 24 │
julia> data_2
4×6 DataFrame
│ Row │ x1 │ x2 │ x3 │ x4 │ x5 │ x6 │
│ │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │
├─────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ 1 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │
│ 2 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
│ 3 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
│ 4 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
julia> data_2[1:1,:] .= data_1[1:1,:] .- data_1[2:2,:]
1×6 SubDataFrame
│ Row │ x1 │ x2 │ x3 │ x4 │ x5 │ x6 │
│ │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │
├─────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ 1 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │
julia> data_2
4×6 DataFrame
│ Row │ x1 │ x2 │ x3 │ x4 │ x5 │ x6 │
│ │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │
├─────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ 1 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │
│ 2 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
│ 3 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
│ 4 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
Как вы можете видеть, хитрость заключается в том, чтобы использовать широковещательные ( .
) и фрагменты ( 1:1
и т.д.), А не отдельные индексы.
Проблема с отдельными индексами заключается в том, что DataFrameRow
сейчас не поддерживается трансляция:
julia> data_2[1,:] .= data_1[1,:] .- data_1[2,:]
ERROR: ArgumentError: broadcasting over `DataFrameRow`s is reserved
поскольку не определено, как будет работать трансляция для NamedTuple
объектов в Base, как вы можете видеть здесь:
julia> (a=1,b=2) .- (a=1,b=2)
ERROR: ArgumentError: broadcasting over dictionaries and `NamedTuple`s is reserved
(как только база поддержит широковещательную передачу NamedTuples
, мы добавим эту поддержку к DataFrameRow
s)
Вариант 3
Это обходной путь к проблеме отсутствия трансляции DataFrameRow
объекта:
julia> data_1 = DataFrame(reshape(1:24, 4, 6))
4×6 DataFrame
│ Row │ x1 │ x2 │ x3 │ x4 │ x5 │ x6 │
│ │ Int64 │ Int64 │ Int64 │ Int64 │ Int64 │ Int64 │
├─────┼───────┼───────┼───────┼───────┼───────┼───────┤
│ 1 │ 1 │ 5 │ 9 │ 13 │ 17 │ 21 │
│ 2 │ 2 │ 6 │ 10 │ 14 │ 18 │ 22 │
│ 3 │ 3 │ 7 │ 11 │ 15 │ 19 │ 23 │
│ 4 │ 4 │ 8 │ 12 │ 16 │ 20 │ 24 │
julia> data_2 = DataFrame(zeros(4,6))
4×6 DataFrame
│ Row │ x1 │ x2 │ x3 │ x4 │ x5 │ x6 │
│ │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │
├─────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ 1 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
│ 2 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
│ 3 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
│ 4 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
julia> data_2[1,:] = Vector(data_1[1,:]) - Vector(data_1[2,:])
DataFrameRow
│ Row │ x1 │ x2 │ x3 │ x4 │ x5 │ x6 │
│ │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │
├─────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ 1 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │
julia> data_2
4×6 DataFrame
│ Row │ x1 │ x2 │ x3 │ x4 │ x5 │ x6 │
│ │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │ Float64 │
├─────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
│ 1 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │ -1.0 │
│ 2 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
│ 3 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
│ 4 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │ 0.0 │
как вы можете видеть, хитрость заключается в преобразовании RHS в Vector
s, которые поддерживают -
.
Наконец (в качестве дополнительной ссылки, которая может быть полезна в некоторых случаях) вы можете написать Vector(data_1[1,:]) - Vector(data_1[2,:])
короче так же, как:
julia> -(Vector.((data_1[1,:],data_1[2,:]))...)
6-element Array{Int64,1}:
-1
-1
-1
-1
-1
-1
Комментарии:
1. Спасибо, БК, как обычно, ты везде и незаменим.