Условные операторы с датафреймами [Julia v1.0] - PullRequest
0 голосов
/ 31 августа 2018

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

if( DataFrame(x=1).x .>1) end

Ошибка:

ОШИБКА: Ошибка типа: не логическое (BitArray {1}) используется в логическом контексте

Есть ли простой обходной путь, который позволил бы мне продолжать использовать DataFrames?

1 Ответ

0 голосов
/ 01 сентября 2018

Выражение:

DataFrame(x=1).x .> 1

Выполняет следующие действия:

  1. Создает DataFrame
  2. Извлекает из него столбец x
  3. Сравнивает все элементы этого столбца с 1, используя векторизованную операцию .> (вещание на языке Юлии)

Фактически вы получаете следующий массив из одного элемента:

julia> DataFrame(x=1).x .> 1
1-element BitArray{1}:
 false

В отличие от R, Юлия различает векторы и скаляры, поэтому это не то же самое, что просто написать false. Более того, оператор if ожидает скаляр, а не вектор, поэтому что-то вроде этого работает:

if 2 > 1
    println("2 is greater than 1")
end

но не как то так:

if DataFrame(x=2).x .> 1
    println("success!")
end

Однако, например, это будет работать:

if (DataFrame(x=2).x .> 1)[1]
    println("success!")
end

при извлечении первого (и только в этом случае) элемента из массива.

Обратите внимание, что в R, если вы передали условному выражению более одного элемента вектора, вы получите следующее предупреждение:

> if (c(T,F)) {
+ print("aaa") } else {print("bbb")}
[1] "aaa"
Warning message:
In
  the condition has length > 1 and only the first element will be used

Просто Джулия при проверке типов в этом случае строже, чем R. В R у вас нет различий между скалярами и векторами, но в Юлии у вас есть.

EDIT:

length(df) возвращает количество столбцов из DataFrame (не количество строк). Если вы выходите из R, вам будет легче запомнить функции nrow и ncol.

Теперь по вашему вопросу вы можете написать:

for i in 1:nrow(df)
    if df.x[i] > 3
        df.y[i] = df.x[i] + 1
    end
end

или

bigx = df.x .> 3
df.y[bigx] = df.x[bigx] .+ 1

или

df.y .= ifelse.(df.x .> 3, df.x .+ 1, df.y)

или использование DataFramesMeta для сокращения записи:

using DataFramesMeta

@with df begin
    df.y .= ifelse.(:x .> 3, :x .+ 1, :y)
end

или

using DataFramesMeta

@byrow! df begin
    if :x > 3
        :y = :x + 1
    end
end
...