Cummulative death by day by country

In R, one would use tidyverse to, for example, aggregate daily deaths of COVID-19 by day and by country [0].

How would one do it in Julia? Is there a package that is similar to Rโ€™s tidyverse? Or does one write a couple of loops self?

Thanks!

[0] https://www.ecdc.europa.eu/sites/default/files/documents/COVID-19-geographic-disbtribution-worldwide-2020-06-24.xlsx

DataFrames.jl

The Queryverse package supports piping data around through transformations, grouping, etc.

Though for this kind of thing I often like to push the data to SQLite and run a SQL query. I find SQL actually quite expressive.

julia> using Dates, DataFrames

julia> data = DataFrame(day = [Date(2020,4,1), Date(2020,4,2), Date(2020,4,1), Date(2020,4,2)], country = [:a, :a, :b, :b], deaths = [10, 20, 30, 40])
4ร—3 DataFrame
โ”‚ Row โ”‚ day        โ”‚ country โ”‚ deaths โ”‚
โ”‚     โ”‚ Date       โ”‚ Symbol  โ”‚ Int64  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 1   โ”‚ 2020-04-01 โ”‚ a       โ”‚ 10     โ”‚
โ”‚ 2   โ”‚ 2020-04-02 โ”‚ a       โ”‚ 20     โ”‚
โ”‚ 3   โ”‚ 2020-04-01 โ”‚ b       โ”‚ 30     โ”‚
โ”‚ 4   โ”‚ 2020-04-02 โ”‚ b       โ”‚ 40     โ”‚

julia> transform(groupby(data, :country), :deaths => cumsum => :deaths)
4ร—3 DataFrame
โ”‚ Row โ”‚ country โ”‚ day        โ”‚ deaths โ”‚
โ”‚     โ”‚ Symbol  โ”‚ Date       โ”‚ Int64  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 1   โ”‚ a       โ”‚ 2020-04-01 โ”‚ 10     โ”‚
โ”‚ 2   โ”‚ a       โ”‚ 2020-04-02 โ”‚ 30     โ”‚
โ”‚ 3   โ”‚ b       โ”‚ 2020-04-01 โ”‚ 30     โ”‚
โ”‚ 4   โ”‚ b       โ”‚ 2020-04-02 โ”‚ 70     โ”‚
4 Likes

The analogue of tidyverse would be queryverse. See e.g.,

1 Like

DataFrames + a few other helper packages will have all you need for this.

The anonymoys function syntax is probably the hardest part to understand coming from R. But hopefully we can make easier syntax soon.

I downloaded the excel file you posted and turned it into a CSV just by opening it in excel and saving it as a .csv file.

using CSV, DataFrames, Pipe, Statistics

df = CSV.File("COVID-19-geographic-disbtribution-worldwide-2020-06-24.csv") |> DataFrame

df_country_month = @pipe df |>
    groupby(_, ["countriesAndTerritories", "month", "year"]) |>
    combine(_, 
    	"cases" => (t -> mean(skipmissing(t))) => "cases",
    	"deaths" => (t -> mean(skipmissing(t))) => "deaths")
1 Like

Arguable, but I think the nicer syntax already exists through function composition:

:cases => mean โˆ˜ skipmissing => :cases
4 Likes

Thank you!

How do u type that symbol in between mean and missing?

\circ

1 Like

How do you type the \circ with reasonable ease if youโ€™re writing code in emacs?

You just need to type \circ[TAB] (assuming emacs is in julia-mode). The first time you do that in a session, it may take time to display the character, but it does work.

1 Like

Thank you.
Do you then store data in an SQL database?

Thank you! Which package contains the transform() function?

I got the following error:

julia> @time transform(groupby(data, :country), :deaths => cumsum => :deaths)
ERROR: UndefVarError: transform not defined
Stacktrace:
 [1] top-level scope at ./util.jl:175

Ah sorry, assumed that as a given as my post was meant to amend Peterโ€™s - itโ€™s in DataFrames, but only as of version 0.21, so make sure youโ€™ve got the latest!

You could, but CSV loading and writing is pretty fast. If your data fits in memory, and youโ€™re using DataFrames to manipulate it, Iโ€™d just stick with CSV

1 Like

Thank you, @Rudy79.

My Gentoo Linux amd64 cannot install ParquetFiles.jl, which is required by Queryverse. I opened an issue on Github: https://github.com/queryverse/ParquetFiles.jl/issues/33

Otherwise, yeah, Queryverse looks great!

DataFrames has the transform function.

Please see my code example above for a MWE with your data.

Thank you!

I think I need to update my DataFrames.jl. However, I do not know what is preventing it from updated to the latest version. My hunch is that a package that depends on an older version of DataFrames.jl prevents DataFrames.jl from being updated.

julia> @time using CSV, DataFrames, Pipe, Statistics
  0.001125 seconds (1.48 k allocations: 78.219 KiB)

julia> @time df = CSV.File("/home/c/Downloads/COVID-19-geographic-disbtribution-worldwide-2020-06-24.csv") |> DataFrame
  0.145597 seconds (27.87 k allocations: 6.840 MiB, 56.48% gc time)
25517ร—11 DataFrame. Omitted printing of 5 columns
โ”‚ Row   โ”‚ dateRep   โ”‚ day   โ”‚ month โ”‚ year  โ”‚ cases โ”‚ deaths โ”‚
โ”‚       โ”‚ String    โ”‚ Int64 โ”‚ Int64 โ”‚ Int64 โ”‚ Int64 โ”‚ Int64  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 1     โ”‚ 6/24/2020 โ”‚ 24    โ”‚ 6     โ”‚ 2020  โ”‚ 338   โ”‚ 20     โ”‚
โ”‚ 2     โ”‚ 6/23/2020 โ”‚ 23    โ”‚ 6     โ”‚ 2020  โ”‚ 310   โ”‚ 17     โ”‚
โ”‚ 3     โ”‚ 6/22/2020 โ”‚ 22    โ”‚ 6     โ”‚ 2020  โ”‚ 409   โ”‚ 12     โ”‚
โ”‚ 4     โ”‚ 6/21/2020 โ”‚ 21    โ”‚ 6     โ”‚ 2020  โ”‚ 546   โ”‚ 21     โ”‚
โ”‚ 5     โ”‚ 6/20/2020 โ”‚ 20    โ”‚ 6     โ”‚ 2020  โ”‚ 346   โ”‚ 2      โ”‚
โ”‚ 6     โ”‚ 6/19/2020 โ”‚ 19    โ”‚ 6     โ”‚ 2020  โ”‚ 658   โ”‚ 42     โ”‚
โ”‚ 7     โ”‚ 6/18/2020 โ”‚ 18    โ”‚ 6     โ”‚ 2020  โ”‚ 564   โ”‚ 13     โ”‚
โ”‚ 8     โ”‚ 6/17/2020 โ”‚ 17    โ”‚ 6     โ”‚ 2020  โ”‚ 783   โ”‚ 13     โ”‚
โ”‚ 9     โ”‚ 6/16/2020 โ”‚ 16    โ”‚ 6     โ”‚ 2020  โ”‚ 761   โ”‚ 7      โ”‚
โ”‚ 10    โ”‚ 6/15/2020 โ”‚ 15    โ”‚ 6     โ”‚ 2020  โ”‚ 664   โ”‚ 20     โ”‚
โ”‚ 11    โ”‚ 6/14/2020 โ”‚ 14    โ”‚ 6     โ”‚ 2020  โ”‚ 556   โ”‚ 5      โ”‚
โ”‚ 12    โ”‚ 6/13/2020 โ”‚ 13    โ”‚ 6     โ”‚ 2020  โ”‚ 656   โ”‚ 20     โ”‚
โ”‚ 13    โ”‚ 6/12/2020 โ”‚ 12    โ”‚ 6     โ”‚ 2020  โ”‚ 747   โ”‚ 21     โ”‚
โ”‚ 14    โ”‚ 6/11/2020 โ”‚ 11    โ”‚ 6     โ”‚ 2020  โ”‚ 684   โ”‚ 21     โ”‚
โ”‚ 15    โ”‚ 6/10/2020 โ”‚ 10    โ”‚ 6     โ”‚ 2020  โ”‚ 542   โ”‚ 15     โ”‚
โ”‚ 16    โ”‚ 6/9/2020  โ”‚ 9     โ”‚ 6     โ”‚ 2020  โ”‚ 575   โ”‚ 12     โ”‚
โ”‚ 17    โ”‚ 6/8/2020  โ”‚ 8     โ”‚ 6     โ”‚ 2020  โ”‚ 791   โ”‚ 30     โ”‚
โ‹ฎ
โ”‚ 25500 โ”‚ 4/7/2020  โ”‚ 7     โ”‚ 4     โ”‚ 2020  โ”‚ 0     โ”‚ 0      โ”‚
โ”‚ 25501 โ”‚ 4/6/2020  โ”‚ 6     โ”‚ 4     โ”‚ 2020  โ”‚ 0     โ”‚ 0      โ”‚
โ”‚ 25502 โ”‚ 4/5/2020  โ”‚ 5     โ”‚ 4     โ”‚ 2020  โ”‚ 0     โ”‚ 0      โ”‚
โ”‚ 25503 โ”‚ 4/4/2020  โ”‚ 4     โ”‚ 4     โ”‚ 2020  โ”‚ 1     โ”‚ 0      โ”‚
โ”‚ 25504 โ”‚ 4/3/2020  โ”‚ 3     โ”‚ 4     โ”‚ 2020  โ”‚ 0     โ”‚ 0      โ”‚
โ”‚ 25505 โ”‚ 4/2/2020  โ”‚ 2     โ”‚ 4     โ”‚ 2020  โ”‚ 0     โ”‚ 0      โ”‚
โ”‚ 25506 โ”‚ 4/1/2020  โ”‚ 1     โ”‚ 4     โ”‚ 2020  โ”‚ 1     โ”‚ 0      โ”‚
โ”‚ 25507 โ”‚ 3/31/2020 โ”‚ 31    โ”‚ 3     โ”‚ 2020  โ”‚ 0     โ”‚ 0      โ”‚
โ”‚ 25508 โ”‚ 3/30/2020 โ”‚ 30    โ”‚ 3     โ”‚ 2020  โ”‚ 0     โ”‚ 0      โ”‚
โ”‚ 25509 โ”‚ 3/29/2020 โ”‚ 29    โ”‚ 3     โ”‚ 2020  โ”‚ 2     โ”‚ 0      โ”‚
โ”‚ 25510 โ”‚ 3/28/2020 โ”‚ 28    โ”‚ 3     โ”‚ 2020  โ”‚ 2     โ”‚ 0      โ”‚
โ”‚ 25511 โ”‚ 3/27/2020 โ”‚ 27    โ”‚ 3     โ”‚ 2020  โ”‚ 0     โ”‚ 0      โ”‚
โ”‚ 25512 โ”‚ 3/26/2020 โ”‚ 26    โ”‚ 3     โ”‚ 2020  โ”‚ 1     โ”‚ 0      โ”‚
โ”‚ 25513 โ”‚ 3/25/2020 โ”‚ 25    โ”‚ 3     โ”‚ 2020  โ”‚ 0     โ”‚ 0      โ”‚
โ”‚ 25514 โ”‚ 3/24/2020 โ”‚ 24    โ”‚ 3     โ”‚ 2020  โ”‚ 0     โ”‚ 1      โ”‚
โ”‚ 25515 โ”‚ 3/23/2020 โ”‚ 23    โ”‚ 3     โ”‚ 2020  โ”‚ 0     โ”‚ 0      โ”‚
โ”‚ 25516 โ”‚ 3/22/2020 โ”‚ 22    โ”‚ 3     โ”‚ 2020  โ”‚ 1     โ”‚ 0      โ”‚
โ”‚ 25517 โ”‚ 3/21/2020 โ”‚ 21    โ”‚ 3     โ”‚ 2020  โ”‚ 1     โ”‚ 0      โ”‚

julia> @time df_country_month = @pipe df |>
           groupby(_, ["countriesAndTerritories", "month", "year"]) |>
           combine(_, 
            "cases" => (t -> mean(skipmissing(t))) => "cases",
            "deaths" => (t -> mean(skipmissing(t))) => "deaths")
ERROR: ArgumentError: idxs[1] has type String; Only Integer or Symbol values allowed when indexing by vector
Stacktrace:
 [1] getindex at /home/c/.julia/packages/DataFrames/S3ZFo/src/other/index.jl:222 [inlined]
 [2] groupby(::DataFrame, ::Array{String,1}; sort::Bool, skipmissing::Bool) at /home/c/.julia/packages/DataFrames/S3ZFo/src/groupeddataframe/grouping.jl:168
 [3] groupby(::DataFrame, ::Array{String,1}) at /home/c/.julia/packages/DataFrames/S3ZFo/src/groupeddataframe/grouping.jl:167
 [4] top-level scope at util.jl:175

julia> @time Pkg.add("DataFrames")
  Resolving package versions...
   Updating `~/.julia/environments/v1.4/Project.toml`
 [no changes]
   Updating `~/.julia/environments/v1.4/Manifest.toml`
 [no changes]
  3.576830 seconds (2.55 M allocations: 168.654 MiB, 5.42% gc time)

julia> @time using DataFrames
  0.000309 seconds (236 allocations: 12.641 KiB)

julia> @time Pkg.status()
Status `~/.julia/environments/v1.4/Project.toml`
  [c9ce4bd3] ArchGDAL v0.3.2
  [6e4b80f9] BenchmarkTools v0.5.0
  [336ed68f] CSV v0.6.1
  [5ae59095] Colors v0.12.1
  [a93c6f00] DataFrames v0.20.2
  [add2ef01] GDAL v1.1.2
  [28b8d3ca] GR v0.49.1
  [dcc97b0b] GeoStats v0.11.6
  [7073ff75] IJulia v1.21.2
  [86fae568] ImageView v0.10.8
  [98b081ad] Literate v2.5.0
  [961ee093] ModelingToolkit v3.6.4
  [9b87118b] PackageCompiler v1.1.1
  [b98c9c47] Pipe v1.2.0
  [91a5bcdd] Plots v1.3.3
  [612083be] Queryverse v0.5.0
  [295af30f] Revise v2.6.7
  [123dc426] SymEngine v0.8.2
  [24249f21] SymPy v1.0.20
  [44d3d7a6] Weave v0.10.2
  [fdbf4ff8] XLSX v0.7.0
  0.200055 seconds (137.18 k allocations: 8.654 MiB)

julia> @time versioninfo()
Julia Version 1.4.2
Commit 44fa15b150* (2020-05-23 18:35 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Pentium(R) 4 CPU 3.00GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-9.0.1 (ORCJIT, nocona)
  4.183625 seconds (2.06 M allocations: 93.365 MiB, 3.33% gc time)

Oh. It turns out that I had a dirty registry. I removed ~/.julia/registries/General and was able to update packages normally. Iโ€™m going to try @pdeffebachโ€™s MWE again now.