Julia - dataframe - Как принудительно привести в качестве значения вектора / нескольких строк скалярные результаты, используя - PullRequest
2 голосов
/ 16 февраля 2020

Длинный и извилистый путь, изучение DataFrames.jl и еще один вопрос.

Я пытаюсь принудительно вызвать функцию, возвращающую скаляр, чтобы отобразить обратно на весь вектор. Я не уверен, что это совершенно ясно, поэтому позвольте мне привести пример:

Допустим, я запускаю следующий (и теперь канонический) пример

df = DataFrame(grp = rand(["a","b"], 100), x= rand(100), y = rand(100), z=rand(100));
by(df, :grp,result= (:x) => (x) -> sum(x))
2×2 DataFrame
│ Row │ grp    │ result  │
│     │ String │ Float64 │
├─────┼────────┼─────────┤
│ 1   │ b      │ 30.431  │
│ 2   │ a      │ 19.9667 │

Я получаю сумму х для каждой группы. Все хорошо. Но по какой-то причине я хочу, чтобы эта сумма каждой группы была приведена для каждой строки в наборе данных

. Я нашел следующий хак

by(df, :grp,result= (:x) => (x) -> x.-x.+sum(x))

, который дает именно то, что я ожидаю

│ Row │ grp    │ result  │
│     │ String │ Float64 │
├─────┼────────┼─────────┤
│ 1   │ b      │ 30.431  │
│ 2   │ b      │ 30.431  │
│ 3   │ b      │ 30.431  │
⋮
│ 98  │ a      │ 19.9667 │
│ 99  │ a      │ 19.9667 │
│ 100 │ a      │ 19.9667 │

Теперь я, по сути, заставляю векторный аспект в функции реализовывать это (я также делаю это самым не элегантным способом).

Мой вопрос: есть ли с помощью () правильный / более хороший способ заставить функцию, возвращающую скаляр, отобразить исходный вектор?

В моем мнение, это было бы очень полезно, а также поможет решить следующие ситуации.

by(df, :grp,result= (:x) => (x) -> sum(x),result2= (:x) => (x) -> mean(x)) # works returns 2 lines 
by(df, :grp,result= (:x) => (x) -> sum(x),result2= (:x) => (x) -> x.-5) # doesnt work (scalar vs vector)
by(df, :grp,result= (:x) => (x) -> x.-x.+sum(x),result2= (:x) => (x) -> x.-5) # works returns 100 lines

Я уверен, что мне чего-то не хватает, любая помощь будет отличной.

1 Ответ

1 голос
/ 16 февраля 2020

В настоящее время by не устанавливает ограничений на количество строк, которые должна возвращать функция преобразования. Единственное ограничение состоит в том, что если передано несколько функций, они должны возвращать одинаковое количество строк.

Вот что вы можете сделать альтернативно:

by(df, :grp,result= :x => x -> fill(sum(x), length(x)))

Общий подход, который вы можете использовать, немного медленнее, но более гибким является использование by следующим образом (я переписываю ваш пример by(df, :grp,result= (:x) => (x) -> sum(x),result2= (:x) => (x) -> x.-5), который не работает):

by(df, :grp) do sdf
    DataFrame(result = sum(sdf.x), result2 = sdf.x .- 5)
end

Здесь вы передаете целое SubDataFrame для функции группировки и использования функции неявного вещания конструктора DataFrame.

Ваш конкретный пример c также может быть записан как:

by(df, :grp, :x => x -> DataFrame(result = sum(x), result2 = x .- 5))

, который является спецификацией c решение, использующее тот факт, что в обоих сгенерированных столбцах для вычислений используется один и тот же столбец из исходного фрейма данных.

...