Cumulative Returns - julia

In R we can do:
cum.ret <- cumprod(1 + df$rets) - 1
I want to do the same thing with Julia here is some dummy data:
# Dummy Data
df = DataFrame(a = 1:10, b = 10*rand(10), Close = 10 * rand(10))
# Calculate Returns
Close = df[:Close]
Close = convert(Array, Close)
df[:Close_Rets] = [NaN; (Close[2:end] ./ Close[1:(end-1)] - 1)]
# Calculate Cumulative Returns
df[:Cum_Ret] = cumprod(((1 .+ df[:Close_Rets])-1),2)
With the output:
julia> head(df)
6×5 DataFrames.DataFrame
│ Row │ a │ b │ Close │ Close_Rets │ Cum_Ret │
├─────┼───┼─────────┼──────────┼────────────┼───────────┤
│ 1 │ 1 │ 6.15507 │ 3.6363 │ NaN │ NaN │
│ 2 │ 2 │ 7.73259 │ 0.98378 │ -0.729456 │ -0.729456 │
│ 3 │ 3 │ 3.64926 │ 7.94633 │ 7.07735 │ 7.07735 │
│ 4 │ 4 │ 5.15762 │ 0.744905 │ -0.906258 │ -0.906258 │
│ 5 │ 5 │ 9.49532 │ 8.51811 │ 10.4352 │ 10.4352 │
│ 6 │ 6 │ 6.14604 │ 5.02165 │ -0.410473 │ -0.410473 │
Anyway to make this work?

Related

Replacing missing values in Juila

I have data-frame contain some missing values, I want to replace all the missing values with the mean of LoanAmount column
df[ismissing.(df.LoanAmount),:LoanAmount]= floor(mean(skipmissing(df.LoanAmount)))
but when I am running above code i am getting
MethodError: no method matching setindex!(::DataFrame, ::Float64, ::BitArray{1}, ::Symbol)
Use skipmissing e.g.:
mean(skipmissing(df.LoanAmount))
Answer to the second, edited question: you should broadcast the assignment using the dot operator (.) as in the example below:
julia> df = DataFrame(col=rand([missing;1:3],10))
10×1 DataFrame
│ Row │ col │
│ │ Int64? │
├─────┼─────────┤
│ 1 │ missing │
│ 2 │ 3 │
│ 3 │ 2 │
│ 4 │ 2 │
│ 5 │ missing │
│ 6 │ missing │
│ 7 │ missing │
│ 8 │ 3 │
│ 9 │ 1 │
│ 10 │ 3 │
julia> df[ismissing.(df.col),:col] .= floor(mean(skipmissing(df.col)));
julia> df
10×1 DataFrame
│ Row │ col │
│ │ Int64? │
├─────┼────────┤
│ 1 │ 2 │
│ 2 │ 3 │
│ 3 │ 2 │
│ 4 │ 2 │
│ 5 │ 2 │
│ 6 │ 2 │
│ 7 │ 2 │
│ 8 │ 3 │
│ 9 │ 1 │
│ 10 │ 3 │
Impute.jl
yet another option is to use Impute.jl as suggested by Bogumil:
Impute.fill(df;value=(x)->floor(mean(x)))
I found this one also,
when we need to replace with mean
replace!(df.col,missing => floor(mean(skipmissing(df[!,:col]))))
when we need to replace with mode
replace!(df.col,missing => mode(skipmissing(df[!,:col])))

Julia: How to create multiple columns with one function in DataFrames.jl

Say I have a column
using DataFrames
df = DataFrame(var = "methodA_mean")
1×3 DataFrame
│ Row │ var │
│ │ String │
├─────┼──────────────┼
│ 1 │ methodA_mean │
│ 2 │ methodB_var │
│ 3 │ methodA_var │
and I would like to create two new columns by extracting A and mean var like so
3×3 DataFrame
│ Row │ var │ ab │ stat │
│ │ String │ String │ String │
├─────┼──────────────┼────────┼────────┤
│ 1 │ methodA_mean │ A │ mean │
│ 2 │ methodB_var │ B │ var │
│ 3 │ methodA_var │ A │ var │
I can write a regex extract "A" or "B" and "mean" and "var" from the var column. But how I output into multiple columns elegantly?
I tried the below and it works, but I feel there should more elegant way to create multiple columns
tmp = match.(r"method(?<ab>A|B)_(?<stat>mean|var)", df.var)
df.ab = getindex.(tmp, :ab)
df.stat = getindex.(tmp, :st)
3×3 DataFrame
│ Row │ var │ ab │ stat │
│ │ String │ SubStri… │ SubStri… │
├─────┼──────────────┼──────────┼──────────┤
│ 1 │ methodA_mean │ A │ mean │
│ 2 │ methodB_var │ B │ var │
│ 3 │ methodA_var │ A │ var │
I am not sure in which part for your code you are looking for an improvement as it seems normal and OK to me, but you could write e.g. this:
julia> insertcols!(df, :ab => last.(first.(df.var, 7), 1), :stat => chop.(df.var, head=8, tail=0))
3×3 DataFrame
│ Row │ var │ ab │ stat │
│ │ String │ String │ SubStri… │
├─────┼──────────────┼────────┼──────────┤
│ 1 │ methodA_mean │ A │ mean │
│ 2 │ methodB_var │ B │ var │
│ 3 │ methodA_var │ A │ var │

How to remove/drop rows of nothing and NaN in Julia dataframe?

I have a df which contains, nothing, NaN and missing. to remove rows which contains missing I can use dropmissing. Is there any methods to deal with NaN and nothing?
Sample df:
│ Row │ x │ y │
│ │ Union…? │ Char │
├─────┼─────────┼──────┤
│ 1 │ 1.0 │ 'a' │
│ 2 │ missing │ 'b' │
│ 3 │ 3.0 │ 'c' │
│ 4 │ │ 'd' │
│ 5 │ 5.0 │ 'e' │
│ 6 │ NaN │ 'f' │
Expected output:
│ Row │ x │ y │
│ │ Any │ Char │
├─────┼─────┼──────┤
│ 1 │ 1.0 │ 'a' │
│ 2 │ 3.0 │ 'c' │
│ 3 │ 5.0 │ 'e' │
What I have tried so far,
Based on my knowledge in Julia I tried this,
df.x = replace(df.x, NaN=>"something", missing=>"something", nothing=>"something")
print(df[df."x".!="something", :])
My code is working as I expected. I feel it's ineffective way of solving this issue.
Is there any separate method to deal with nothing and NaN?
You can do e.g. this:
julia> df = DataFrame(x=[1,missing,3,nothing,5,NaN], y='a':'f')
6×2 DataFrame
│ Row │ x │ y │
│ │ Union…? │ Char │
├─────┼─────────┼──────┤
│ 1 │ 1.0 │ 'a' │
│ 2 │ missing │ 'b' │
│ 3 │ 3.0 │ 'c' │
│ 4 │ │ 'd' │
│ 5 │ 5.0 │ 'e' │
│ 6 │ NaN │ 'f' │
julia> filter(:x => x -> !any(f -> f(x), (ismissing, isnothing, isnan)), df)
3×2 DataFrame
│ Row │ x │ y │
│ │ Union…? │ Char │
├─────┼─────────┼──────┤
│ 1 │ 1.0 │ 'a' │
│ 2 │ 3.0 │ 'c' │
│ 3 │ 5.0 │ 'e' │
Note that here the order of checks is important, as isnan should be last, because otherwise this check will fail for missing or nothing value.
You could also have written it more directly as:
julia> filter(:x => x -> !(ismissing(x) || isnothing(x) || isnan(x)), df)
3×2 DataFrame
│ Row │ x │ y │
│ │ Union…? │ Char │
├─────┼─────────┼──────┤
│ 1 │ 1.0 │ 'a' │
│ 2 │ 3.0 │ 'c' │
│ 3 │ 5.0 │ 'e' │
but I felt that the example with any is more extensible (you can then store the list of predicates to check in a variable).
The reason why only a function for removing missing is provided in DataFrames.jl is that this is what is normally considered to be a valid but desirable to remove value in data science pipelines.
Normally in Julia when you see nothing or NaN you probably want to handle them in a different way than missing as they most likely signal there is some error in the data or in processing of data (as opposed to missing which signals that the data was just not collected).

How to append zero values for eache DateTime x-axis on a dataframe in julia

I want to plot a data, but it's x-axis is time, for the missing value in each half-hour, I wish to fill zero.
using CSV, DataFrames, Dates
s="ts, v
2020-01-01T01:00:00, 3
2020-01-01T04:00:00, 6
2020-01-01T05:00:00, 1"
d=CSV.read(IOBuffer(s))
I expect to expand the d like d2
s2="ts, v
2020-01-01T01:00:00, 3
2020-01-01T01:30:00, 0
2020-01-01T02:00:00, 0
2020-01-01T02:30:00, 0
2020-01-01T03:00:00, 0
2020-01-01T03:30:00, 0
2020-01-01T04:00:00, 6
2020-01-01T04:30:00, 0
2020-01-01T05:00:00, 1"
d2=CSV.read(IOBuffer(s2))
I would probably do the following:
# Create half-hourly data frame with zeros from first to last observation
julia> df = DataFrame(ts = minimum(d.ts):Minute(30):maximum(d.ts), v_filled = 0);
# Join the existing observations onto this dataframe
julia> df = join(df, d, on = :ts, kind = :left);
# Replace zeros with observations where available
julia> df[.!ismissing.(df.v), :v_filled] = df[.!ismissing.(df.v), :v];
julia> df
9×3 DataFrame
│ Row │ ts │ v_filled │ v │
│ │ DateTime │ Int64 │ Int64⍰ │
├─────┼─────────────────────┼──────────┼─────────┤
│ 1 │ 2020-01-01T01:00:00 │ 3 │ 3 │
│ 2 │ 2020-01-01T01:30:00 │ 0 │ missing │
│ 3 │ 2020-01-01T02:00:00 │ 0 │ missing │
│ 4 │ 2020-01-01T02:30:00 │ 0 │ missing │
│ 5 │ 2020-01-01T03:00:00 │ 0 │ missing │
│ 6 │ 2020-01-01T03:30:00 │ 0 │ missing │
│ 7 │ 2020-01-01T04:00:00 │ 6 │ 6 │
│ 8 │ 2020-01-01T04:30:00 │ 0 │ missing │
│ 9 │ 2020-01-01T05:00:00 │ 1 │ 1 │

Multiply two data frame columns

So I tried this:
df[:new_col] = (df[:col_one ] .* [df[:col_two]])
It produces a wild result.
I then though to iterate row wise by access the data frame index:
v = Float64[]
for i in 1:nrow(df)
z = df[[i],[:col_one]] * df[[i],[:col_two]]
append!(v,z)
end
This however does not work. Any ideas?
What are my options from here? Pull the data from a data frame and make a vector?
** Update **
df = DataFrame(a = 1:10, b = 10*rand(10), c = 10 * rand(10))
df[:new_d] = df[:b] .* df[:c]
For output:
julia> head(df)
6×4 DataFrames.DataFrame
│ Row │ a │ b │ c │ new_d │
├─────┼───┼─────────┼─────────┼─────────┤
│ 1 │ 1 │ 6.67916 │ 8.38096 │ 55.9778 │
│ 2 │ 2 │ 7.50056 │ 5.26593 │ 39.4974 │
│ 3 │ 3 │ 7.76419 │ 3.54361 │ 27.5133 │
│ 4 │ 4 │ 2.86521 │ 8.41335 │ 24.1061 │
│ 5 │ 5 │ 3.7417 │ 8.10884 │ 30.3409 │
│ 6 │ 6 │ 7.52014 │ 2.61603 │ 19.6729 │

Resources