У меня есть DataFrame
df
, который я получил из базы данных Postgres следующим образом.
using DataFrames, LibPQ
con = LibPQ.Connection(con_string)
result = execute(con, "SELECT * FROM [table]")
df = DataFrame(result)
close(con)
Извините, я не могу сделать это воспроизводимым.
Теперь либо DataFrames
, либо LibPQ
превращает столбцы NUMERIC
Postgres в тип Decimals.Decimal
. Это может быть круто для максимальной точности, но это создает проблемы, когда я пытаюсь построить что-либо с этими столбцами.
eltype.(eachcol(df))
5-element Vector{Union}:
Union{Missing, String}
Union{Missing, TimeZones.ZonedDateTime}
Union{Missing, Int32}
Union{Missing, Date}
Union{Missing, Decimals.Decimal}
Как очень хорошо объяснил здесь Богумил Камински, я могу изменить столбцы определенного типа на другой тип. Предостережение в том, что я не могу даже проверить, относится ли столбец к типу Union{Missing, Decimals.Decimal}
, потому что пакет Decimals
не загружен. Ладно, подумал я, давайте тогда загрузим пакет Decimals
- но не получается, потому что сначала нужно установить пакет...
Есть ли другой способ превратить эти столбцы в Float64
s? Без установки всего пакета? Я знаю, что могу изменить типы столбцов, используя имена столбцов, например
df.my_column = Float64.(df.my_column)
но я не буду знать соответствующие имена столбцов заранее.
Черт возьми, ты прав. Почему я не подумал об этом! Хочешь сделать это ответом?
Вы можете использовать Union{Missing, AbstractFloat}
в качестве селектора типа, как Decimal <: AbstractFloat
.
Поскольку Union{Missing, AbstractFloat}
не является конкретным типом, вам нужно написать eltype(col) <: Union{Missing, AbstractFloat}
, чтобы проверить условие подтипа.
Кстати, если у вас установлен LibPQ.jl, то у вас также есть доступ к Decimals.jl:
julia> LibPQ.Decimals.Decimal
Decimals.Decimal
Хм, я с таким энтузиазмом согласился, но теперь, когда я попробовал это, я понял, что на самом деле это не работает. Выполнение mapcols(df) do col eltype(col) === Union{Missing, AbstractFloat} ? Float64.(col) : col end
не преобразует ни один из столбцов.
Я добавил обновление ===
проверки на точное равенство типов.
Хорошо, извините, что не понял, но ==
тоже не работает.
Вам нужно использовать <:
, а не ==
. <:
проводит тест на подтип. (см. обновление в моем ответе)
Я добавил комментарий о том, как вы можете получить доступ к Decimals.jl, не добавляя его, если у вас уже есть LibPQ.jl в вашем Project.toml.
Вы можете использовать identity
, чтобы правильно ввести каждый столбец в DataFrame
.
julia> df=DataFrame(A=Number[1,2],B=Union{Missing,AbstractFloat}[3,4])
2×2 DataFrame
Row │ A B
│ Number Abstract…?
─────┼────────────────────
1 │ 1 3.0
2 │ 2 4.0
julia> identity.(df)
2×2 DataFrame
Row │ A B
│ Int64 Float64
─────┼────────────────
1 │ 1 3.0
2 │ 2 4.0
Я не думаю, что это сработает в данном случае, так как цель состоит не просто в том, чтобы получить самый узкий тип значений, а в том, чтобы преобразовать их в другой тип.
Вопрос заключается в том, чтобы преобразовать в Float64
, но, поскольку он говорит: «Это создает проблемы, когда я пытаюсь построить что-либо с этими столбцами», я ответил, как преобразовать в тип, который можно построить. Это полезно, потому что его можно записать коротко, если достаточно преобразования в самый узкий тип вместо преобразования в конкретный другой тип.
Вы можете использовать
Union{Missing, AbstractFloat}
в качестве селектора типа, какDecimal <: AbstractFloat
.