User Tools

Site Tools


dataframecomplex

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

dataframecomplex [2018/12/27 14:34] (current)
Line 1: Line 1:
 +
 +~~CLOSETOC~~
 +
 +~~TOC 1-3 wide~~
 +
 +---
 +
 +|  [[dataframeintro|DataFrame Introduction]] ​ |  [[dataframemissing|DataFrame Missing and NaN]]  |  [[dataframecolumnops|DataFrame Column Operations]] ​ |  [[dataframerowops|DataFrame Row Operations]] ​ |  [[fileformats|DataFrame Input/​Output]] ​ |  DataFrame Complex Operations ​ |
 +
 +```juliarepl
 +julia> pkgchk.( [ "​julia"​ => v"​1.0.3",​ "​DataFrames"​ => v"​0.14.1",​ "​Missings"​ => v"​0.3.1"​ ] );
 +
 +```
 +
 +---
 +
 +
 +IMPORTANT For data sets that are larger than your RAM memory, consider using [JuliaDB](http://​juliadb.org/​latest/​index.html). ​ Many of the operations discussed in this chapter have direct equivalents in JuliaDB. ​ however, because JuliaDB is explicitly disk-based (rather than memory-based),​ the performance will be much better. ​ See also [[fileformats#​juliadb|JuliaDB]].
 +
 +---
 +
 +# Sorting DataFrames
 +
 +
 +## Sorting by Column Content
 +
 +```juliarepl
 +julia> using DataFrames, Serialization
 +
 +julia> x1= vcat(99,​collect(1:​2:​9));​ df= DataFrame( n1=x1, n2=sin.(x1) ); df[3,:n2]= NaN; df[[:n2]]= allowmissing!(df[[:​n2]]);​ df[4,:n2]= missing;
 +
 +julia> sort(df, :n2)
 +6×2 DataFrame
 +│ Row │ n1    │ n2        │
 +│     │ Int64 │ Float64⍰ ​ │
 +├─────┼───────┼───────────┤
 +│ 1   │ 99    │ -0.999207 │
 +│ 2   │ 9     │ 0.412118 ​ │
 +│ 3   │ 7     │ 0.656987 ​ │
 +│ 4   │ 1     │ 0.841471 ​ │
 +│ 5   │ 3     │ NaN       │
 +│ 6   │ 5     │ missing ​  │
 +
 +julia> open("​tmpsample-df1.jls",​ "​w"​) do ofile; serialize(ofile,​ df); end;#​do ​       ## save to disk
 +
 +```
 +
 +To specify multiple columns to break ties, pass an array, such as `cols=[ :n2 , :n1 ]`.
 +
 +
 +### Sorting with an Order Function
 +
 +```juliarepl
 +julia> using DataFrames, Serialization; ​ df= deserialize( open("​tmpsample-df1.jls"​) );
 +
 +julia> sortperm( df[:n2] )
 +6-element Array{Int64,​1}:​
 + 1
 + 6
 + 5
 + 2
 + 3
 + 4
 +
 +julia> df= df[ sortperm( df[:n2] ), : ]
 +6×2 DataFrame
 +│ Row │ n1    │ n2        │
 +│     │ Int64 │ Float64⍰ ​ │
 +├─────┼───────┼───────────┤
 +│ 1   │ 99    │ -0.999207 │
 +│ 2   │ 9     │ 0.412118 ​ │
 +│ 3   │ 7     │ 0.656987 ​ │
 +│ 4   │ 1     │ 0.841471 ​ │
 +│ 5   │ 3     │ NaN       │
 +│ 6   │ 5     │ missing ​  │
 +
 +```
 +
 +
 +
 +
 +# BY Group Operations
 +
 +For this section, use the following example:
 +
 +```juliarepl
 +julia> using DataFrames, Serialization
 +
 +julia> df= DataFrame( n1=1:9, n2= [1:9;].^2, cat=[ '​A','​B','​A',​ '​B','​C','​B',​ '​C','​A','​C'​ ] )
 +9×3 DataFrame
 +│ Row │ n1    │ n2    │ cat  │
 +│     │ Int64 │ Int64 │ Char │
 +├─────┼───────┼───────┼──────┤
 +│ 1   │ 1     │ 1     │ '​A' ​ │
 +│ 2   │ 2     │ 4     │ '​B' ​ │
 +│ 3   │ 3     │ 9     │ '​A' ​ │
 +│ 4   │ 4     │ 16    │ '​B' ​ │
 +│ 5   │ 5     │ 25    │ '​C' ​ │
 +│ 6   │ 6     │ 36    │ '​B' ​ │
 +│ 7   │ 7     │ 49    │ '​C' ​ │
 +│ 8   │ 8     │ 64    │ '​A' ​ │
 +│ 9   │ 9     │ 81    │ '​C' ​ │
 +
 +julia> open("​tmpsample-df2.jls",​ "​w"​) do ofile; serialize(ofile,​ df); end;#​do# ​       ## save to disk
 +
 +```
 +
 +
 +
 +### Split: Splitting Into Multiple DataFrames
 + 
 +(Splitting is rarely necessary, because `by()` operations discussed in the next subsection have this functionality already built-in.)
 +
 +```juliarepl
 +julia> using DataFrames, Serialization; ​ df= deserialize( open("​tmpsample-df2.jls"​) );
 +
 +julia> groupby(df, :cat)
 +GroupedDataFrame{DataFrame} with 3 groups based on key: :cat
 +First Group: 3 rows
 +│ Row │ n1    │ n2    │ cat  │
 +│     │ Int64 │ Int64 │ Char │
 +├─────┼───────┼───────┼──────┤
 +│ 1   │ 1     │ 1     │ '​A' ​ │
 +│ 2   │ 3     │ 9     │ '​A' ​ │
 +│ 3   │ 8     │ 64    │ '​A' ​ │
 +
 +Last Group: 3 rows
 +│ Row │ n1    │ n2    │ cat  │
 +│     │ Int64 │ Int64 │ Char │
 +├─────┼───────┼───────┼──────┤
 +│ 1   │ 5     │ 25    │ '​C' ​ │
 +│ 2   │ 7     │ 49    │ '​C' ​ │
 +│ 3   │ 9     │ 81    │ '​C' ​ │
 +
 +```
 +
 +
 +### Split-Apply:​ Operation on Split Data Frames
 +
 +```juliarepl
 +julia> using DataFrames, Serialization; ​ df= deserialize( open("​tmpsample-df2.jls"​) );
 +
 +julia> by( df, :cat ) do x ; println( x, "​\n"​ ) ; end ;
 +3×3 SubDataFrame{Array{Int64,​1}}
 +│ Row │ n1    │ n2    │ cat  │
 +│     │ Int64 │ Int64 │ Char │
 +├─────┼───────┼───────┼──────┤
 +│ 1   │ 1     │ 1     │ '​A' ​ │
 +│ 2   │ 3     │ 9     │ '​A' ​ │
 +│ 3   │ 8     │ 64    │ '​A' ​ │
 +
 +3×3 SubDataFrame{Array{Int64,​1}}
 +│ Row │ n1    │ n2    │ cat  │
 +│     │ Int64 │ Int64 │ Char │
 +├─────┼───────┼───────┼──────┤
 +│ 1   │ 2     │ 4     │ '​B' ​ │
 +│ 2   │ 4     │ 16    │ '​B' ​ │
 +│ 3   │ 6     │ 36    │ '​B' ​ │
 +
 +3×3 SubDataFrame{Array{Int64,​1}}
 +│ Row │ n1    │ n2    │ cat  │
 +│     │ Int64 │ Int64 │ Char │
 +├─────┼───────┼───────┼──────┤
 +│ 1   │ 5     │ 25    │ '​C' ​ │
 +│ 2   │ 7     │ 49    │ '​C' ​ │
 +│ 3   │ 9     │ 81    │ '​C' ​ │
 +
 +```
 +
 +
 +
 +### Split-Apply-Combine:​ Simple Functions by Category (By)
 +
 +#### Simplest Example
 +
 +To obtain the number of rows in each category,
 +
 +```juliarepl
 +julia> using DataFrames, Serialization; ​ df= deserialize( open("​tmpsample-df2.jls"​) );
 +
 +julia> by(df, :cat, nrow)
 +3×2 DataFrame
 +│ Row │ cat  │ x1    │
 +│     │ Char │ Int64 │
 +├─────┼──────┼───────┤
 +│ 1   │ '​A' ​ │ 3     │
 +│ 2   │ '​B' ​ │ 3     │
 +│ 3   │ '​C' ​ │ 3     │
 +
 +```
 +
 +
 +#### Mean of Column by Category in Other Column
 +
 +```juliarepl
 +julia> using DataFrames, Serialization,​ Statistics; ​ df= deserialize( open("​tmpsample-df2.jls"​) );
 +
 +julia> by( df, :cat, d->​mean(d[:,:​n1]) )
 +3×2 DataFrame
 +│ Row │ cat  │ x1      │
 +│     │ Char │ Float64 │
 +├─────┼──────┼─────────┤
 +│ 1   │ '​A' ​ │ 4.0     │
 +│ 2   │ '​B' ​ │ 4.0     │
 +│ 3   │ '​C' ​ │ 7.0     │
 +
 +```
 +
 +#### Display Operations on Columns by Category in Other Column
 +
 +```juliarepl
 +julia> using DataFrames, Serialization,​ Statistics; ​ df= deserialize( open("​tmpsample-df2.jls"​) );
 +
 +julia> by( df, :cat ) do x ; println( mean(x[:,:​n2] ) ) ; end#do;
 +24.666666666666668
 +18.666666666666668
 +51.666666666666664
 +```
 +
 +
 +#### Mean of All Columns by Category in Other Column
 +
 +```juliarepl
 +julia> using DataFrames, Serialization,​ Statistics; ​ df= deserialize( open("​tmpsample-df2.jls"​) );
 +
 +julia> aggregate(df,​ :cat, mean)
 +3×3 DataFrame
 +│ Row │ cat  │ n1_mean │ n2_mean │
 +│     │ Char │ Float64 │ Float64 │
 +├─────┼──────┼─────────┼─────────┤
 +│ 1   │ '​A' ​ │ 4.0     │ 24.6667 │
 +│ 2   │ '​B' ​ │ 4.0     │ 18.6667 │
 +│ 3   │ '​C' ​ │ 7.0     │ 51.6667 │
 +
 +```
 +
 +
 +
 +
 +#### Arbitrary Functions on Arbitrary Columns by Category in Some Column
 +
 +```juliarepl
 +julia> using DataFrames, Serialization,​ Statistics; ​ df= deserialize( open("​tmpsample-df2.jls"​) );
 +
 +julia> by( df, :cat ) do x ; [ mean(x[:,:​n2]) ​ var(x[:,:​n2]) ] ; end
 +3×3 DataFrame
 +│ Row │ cat  │ x1      │ x2      │
 +│     │ Char │ Float64 │ Float64 │
 +├─────┼──────┼─────────┼─────────┤
 +│ 1   │ '​A' ​ │ 24.6667 │ 1176.33 │
 +│ 2   │ '​B' ​ │ 18.6667 │ 261.333 │
 +│ 3   │ '​C' ​ │ 51.6667 │ 789.333 │
 +
 +```
 +
 +
 +### Split-Apply-Combine-Return:​ Original-Size Vector By Group Operation (aka R' ave)
 +
 +**Example (Continued)**:​ Create a vector equal-length with a data frame, in which each element is the respective category'​s own average.
 +
 +```juliarepl
 +julia> using DataFrames, Serialization,​ Statistics; ​ df= deserialize( open("​tmpsample-df2.jls"​) );
 +
 +julia> infodf= by( df, :cat ) do x ;  mean(x[:,:​n2]) ​ ; end#do
 +3×2 DataFrame
 +│ Row │ cat  │ x1      │
 +│     │ Char │ Float64 │
 +├─────┼──────┼─────────┤
 +│ 1   │ '​A' ​ │ 24.6667 │
 +│ 2   │ '​B' ​ │ 18.6667 │
 +│ 3   │ '​C' ​ │ 51.6667 │
 +
 +julia> classcat= infodf[:​cat]
 +3-element Array{Char,​1}:​
 + '​A'​
 + '​B'​
 + '​C'​
 +
 +julia> valuecat= infodf[:x1]
 +3-element Array{Float64,​1}:​
 + ​24.666666666666668
 + ​18.666666666666668
 + ​51.666666666666664
 +
 +julia> di= Dict{eltype(classcat),​ eltype(valuecat)}()
 +Dict{Char,​Float64} with 0 entries
 +
 +julia> for i in 1:​length(classcat);​ di[ classcat[i] ]= valuecat[i];​ end#for
 +
 +julia> map( x->​di[x],​ df[:cat] )
 +9-element Array{Float64,​1}:​
 + ​24.666666666666668
 + ​18.666666666666668
 + ​24.666666666666668
 + ​18.666666666666668
 + ​51.666666666666664
 + ​18.666666666666668
 + ​51.666666666666664
 + ​24.666666666666668
 + ​51.666666666666664
 +
 +```
 +
 +See also [[unistats#​classifications|Univariate Statistics -- Classifications]] for calculating an original-size vector of group means (R `ave()`).
 +
 +
 +For another example, consider a panel data set in a data frame that has a '​yyyymmdd'​ field, and you would like to get statistics by year.  This could be done as follows:
 +
 +```julianoeval
 +julia> d[:,:year]= Int.(trunc.(d[:​yyyymmdd]/​10000));​
 +
 +julia> by( d, :year, x -> cor(x[:,:​a],​x[:,:​b]) )
 +5×2 DataFrame
 +│ Row │ year  │ x1         │
 +│     │ Int64 │ Float64 ​   │
 +├─────┼───────┼────────────┤
 +│ 1   │ 1963  │ -0.182199 ​ │
 +│ 2   │ 1964  │ -0.0975857 │
 +│ 3   │ 1965  │ 0.27817 ​   │
 +│ 4   │ 1966  │ 0.139457 ​  │
 +│ 5   │ 1967  │ 0.232043 ​  │
 +```
 +
 +
 +
 +## Converting Wide and Long Formats
 +
 +```juliarepl
 +julia> using DataFrames, Random
 +
 +julia> Random.seed!(0);​ widish= DataFrame( a=1:3, b='​a':'​c',​ c=randn(3), d=randn(3), e= '​A':'​C'​ )
 +3×5 DataFrame
 +│ Row │ a     │ b    │ c         │ d         │ e    │
 +│     │ Int64 │ Char │ Float64 ​  │ Float64 ​  │ Char │
 +├─────┼───────┼──────┼───────────┼───────────┼──────┤
 +│ 1   │ 1     │ '​a' ​ │ 0.679107 ​ │ -0.134854 │ '​A' ​ │
 +│ 2   │ 2     │ '​b' ​ │ 0.828413 ​ │ 0.586617 ​ │ '​B' ​ │
 +│ 3   │ 3     │ '​c' ​ │ -0.353007 │ 0.297336 ​ │ '​C' ​ │
 +
 +```
 +
 +### From Wide to Long
 +
 +There are two versions: `stack()` requests the variables that are to become stacked, while `melt()` requests the non-stacked variables.
 +
 +```juliarepl
 +julia> using DataFrames, Random
 +
 +julia> Random.seed!(0);​ widish= DataFrame( a=1:3, b='​a':'​c',​ c=randn(3), d=randn(3), e= '​A':'​C'​ );
 +
 +julia> longish= stack( widish, [:c,:d] )     ## the third argument defaults to others, here [:a,:b,:e]
 +6×5 DataFrame
 +│ Row │ variable │ value     │ a     │ b    │ e    │
 +│     │ Symbol ​  │ Float64 ​  │ Int64 │ Char │ Char │
 +├─────┼──────────┼───────────┼───────┼──────┼──────┤
 +│ 1   │ c        │ 0.679107 ​ │ 1     │ '​a' ​ │ '​A' ​ │
 +│ 2   │ c        │ 0.828413 ​ │ 2     │ '​b' ​ │ '​B' ​ │
 +│ 3   │ c        │ -0.353007 │ 3     │ '​c' ​ │ '​C' ​ │
 +│ 4   │ d        │ -0.134854 │ 1     │ '​a' ​ │ '​A' ​ │
 +│ 5   │ d        │ 0.586617 ​ │ 2     │ '​b' ​ │ '​B' ​ │
 +│ 6   │ d        │ 0.297336 ​ │ 3     │ '​c' ​ │ '​C' ​ │
 +
 +julia> stack( widish, [:c, :d] ) == melt( widish, [:a,:b,:e] )
 +true
 +
 +```
 +
 +### From Long to Wide
 +
 +```juliarepl
 +julia> using DataFrames, Random
 +
 +julia> Random.seed!(0);​ widish= DataFrame( a=1:3, b='​a':'​c',​ c=randn(3), d=randn(3), e= '​A':'​C'​ ); longish= stack( widish, [:c,:d] );
 +
 +julia> unstack( longish, :variable, :value )
 +3×5 DataFrame
 +│ Row │ a     │ b    │ e    │ c         │ d         │
 +│     │ Int64 │ Char │ Char │ Float64⍰ ​ │ Float64⍰ ​ │
 +├─────┼───────┼──────┼──────┼───────────┼───────────┤
 +│ 1   │ 1     │ '​a' ​ │ '​A' ​ │ 0.679107 ​ │ -0.134854 │
 +│ 2   │ 2     │ '​b' ​ │ '​B' ​ │ 0.828413 ​ │ 0.586617 ​ │
 +│ 3   │ 3     │ '​c' ​ │ '​C' ​ │ -0.353007 │ 0.297336 ​ │
 +
 +```
 +
 +
 +
 +# Merging Two Data Frames
 +
 +The docs for [Dataframe Joins](https://​juliadata.github.io/​DataFrames.jl/​stable/​man/​joins.html) contains an excellent explanation.
 +
 +## Merging DataFrames with Unique Values in Fields
 +
 +Easiest to follow:
 +
 +```juliarepl
 +julia> using DataFrames
 +
 +julia> df1= DataFrame( id=[1:3;], v1=['​A':'​C';​] )
 +3×2 DataFrame
 +│ Row │ id    │ v1   │
 +│     │ Int64 │ Char │
 +├─────┼───────┼──────┤
 +│ 1   │ 1     │ '​A' ​ │
 +│ 2   │ 2     │ '​B' ​ │
 +│ 3   │ 3     │ '​C' ​ │
 +
 +julia> df2= DataFrame( id=[1,4], v2=['​a','​d'​] )
 +2×2 DataFrame
 +│ Row │ id    │ v2   │
 +│     │ Int64 │ Char │
 +├─────┼───────┼──────┤
 +│ 1   │ 1     │ '​a' ​ │
 +│ 2   │ 4     │ '​d' ​ │
 +
 +julia> join( df1, df2, on=:id, kind= :inner )        ## inner = intersection of both
 +1×3 DataFrame
 +│ Row │ id    │ v1   │ v2   │
 +│     │ Int64 │ Char │ Char │
 +├─────┼───────┼──────┼──────┤
 +│ 1   │ 1     │ '​A' ​ │ '​a' ​ │
 +
 +julia> join( df1, df2, on=:id, kind= :semi )         ## semi = like both, but keep only df1
 +1×2 DataFrame
 +│ Row │ id    │ v1   │
 +│     │ Int64 │ Char │
 +├─────┼───────┼──────┤
 +│ 1   │ 1     │ '​A' ​ │
 +
 +julia> join( df1, df2, on=:id, kind= :left )         ## all left df1 obs included
 +3×3 DataFrame
 +│ Row │ id    │ v1   │ v2      │
 +│     │ Int64 │ Char │ Char⍰ ​  │
 +├─────┼───────┼──────┼─────────┤
 +│ 1   │ 1     │ '​A' ​ │ '​a' ​    │
 +│ 2   │ 2     │ '​B' ​ │ missing │
 +│ 3   │ 3     │ '​C' ​ │ missing │
 +
 +julia> join( df1, df2, on=:id, kind= :right )         ## all right df2 obs included
 +2×3 DataFrame
 +│ Row │ id    │ v1      │ v2   │
 +│     │ Int64 │ Char⍰ ​  │ Char │
 +├─────┼───────┼─────────┼──────┤
 +│ 1   │ 1     │ '​A' ​    │ '​a' ​ │
 +│ 2   │ 4     │ missing │ '​d' ​ │
 +
 +julia> join( df1, df2, on=:id, kind= :outer )         ## merge and keep all
 +4×3 DataFrame
 +│ Row │ id    │ v1      │ v2      │
 +│     │ Int64 │ Char⍰ ​  │ Char⍰ ​  │
 +├─────┼───────┼─────────┼─────────┤
 +│ 1   │ 1     │ '​A' ​    │ '​a' ​    │
 +│ 2   │ 2     │ '​B' ​    │ missing │
 +│ 3   │ 3     │ '​C' ​    │ missing │
 +│ 4   │ 4     │ missing │ '​d' ​    │
 +
 +julia> join( df1, df2, on=:id, kind= :anti )          ## from df1, not in df2
 +2×2 DataFrame
 +│ Row │ id    │ v1   │
 +│     │ Int64 │ Char │
 +├─────┼───────┼──────┤
 +│ 1   │ 2     │ '​B' ​ │
 +│ 2   │ 3     │ '​C' ​ │
 +
 +```
 +
 +
 +
 +## Merging With Duplicate Values in Fields
 +
 +Modestly more difficult to follow. ​ Multiple duplicates can create crossproduct number of observations.
 +
 +```juliarepl
 +julia> using DataFrames
 +
 +julia> df1= DataFrame( id=[ 1, 2, 3, 1, 4, 4 ], v1= ["​A1","​B","​C","​A2","​E1","​E2"​] )  ## 1,4 are dup; 2,3 are unique
 +6×2 DataFrame
 +│ Row │ id    │ v1     │
 +│     │ Int64 │ String │
 +├─────┼───────┼────────┤
 +│ 1   │ 1     │ A1     │
 +│ 2   │ 2     │ B      │
 +│ 3   │ 3     │ C      │
 +│ 4   │ 1     │ A2     │
 +│ 5   │ 4     │ E1     │
 +│ 6   │ 4     │ E2     │
 +
 +julia> df2= DataFrame( id=[ 1, 4, 4, 5, 5, 6 ], v2= ["​a","​d1","​d2","​e1","​e2","​f"​] )  ## 4,5 are dup; 1,6 are unique
 +6×2 DataFrame
 +│ Row │ id    │ v2     │
 +│     │ Int64 │ String │
 +├─────┼───────┼────────┤
 +│ 1   │ 1     │ a      │
 +│ 2   │ 4     │ d1     │
 +│ 3   │ 4     │ d2     │
 +│ 4   │ 5     │ e1     │
 +│ 5   │ 5     │ e2     │
 +│ 6   │ 6     │ f      │
 +
 +julia> join( df1, df2, on= :id, kind= :inner )        ## inner = intersection of both --- id=4 has 2x2 rows
 +6×3 DataFrame
 +│ Row │ id    │ v1     │ v2     │
 +│     │ Int64 │ String │ String │
 +├─────┼───────┼────────┼────────┤
 +│ 1   │ 1     │ A1     │ a      │
 +│ 2   │ 1     │ A2     │ a      │
 +│ 3   │ 4     │ E1     │ d1     │
 +│ 4   │ 4     │ E1     │ d2     │
 +│ 5   │ 4     │ E2     │ d1     │
 +│ 6   │ 4     │ E2     │ d2     │
 +
 +julia> join( df1, df2, on= :id, kind= :semi )         ## semi = like both, but keep only df1 --- id=4 has only two rows
 +4×2 DataFrame
 +│ Row │ id    │ v1     │
 +│     │ Int64 │ String │
 +├─────┼───────┼────────┤
 +│ 1   │ 1     │ A1     │
 +│ 2   │ 1     │ A2     │
 +│ 3   │ 4     │ E1     │
 +│ 4   │ 4     │ E2     │
 +
 +julia> join( df1, df2, on= :id, kind= :left )         ## all left df1 obs included
 +8×3 DataFrame
 +│ Row │ id    │ v1     │ v2      │
 +│     │ Int64 │ String │ String⍰ │
 +├─────┼───────┼────────┼─────────┤
 +│ 1   │ 1     │ A1     │ a       │
 +│ 2   │ 2     │ B      │ missing │
 +│ 3   │ 3     │ C      │ missing │
 +│ 4   │ 1     │ A2     │ a       │
 +│ 5   │ 4     │ E1     │ d1      │
 +│ 6   │ 4     │ E1     │ d2      │
 +│ 7   │ 4     │ E2     │ d1      │
 +│ 8   │ 4     │ E2     │ d2      │
 +
 +julia> join( df1, df2, on= :id, kind= :right )         ## all right df2 obs included
 +9×3 DataFrame
 +│ Row │ id    │ v1      │ v2     │
 +│     │ Int64 │ String⍰ │ String │
 +├─────┼───────┼─────────┼────────┤
 +│ 1   │ 1     │ A1      │ a      │
 +│ 2   │ 1     │ A2      │ a      │
 +│ 3   │ 4     │ E1      │ d1     │
 +│ 4   │ 4     │ E2      │ d1     │
 +│ 5   │ 4     │ E1      │ d2     │
 +│ 6   │ 4     │ E2      │ d2     │
 +│ 7   │ 5     │ missing │ e1     │
 +│ 8   │ 5     │ missing │ e2     │
 +│ 9   │ 6     │ missing │ f      │
 +
 +julia> join( df1, df2, on= :id, kind= :outer )         ## merge and keep all
 +11×3 DataFrame
 +│ Row │ id    │ v1      │ v2      │
 +│     │ Int64 │ String⍰ │ String⍰ │
 +├─────┼───────┼─────────┼─────────┤
 +│ 1   │ 1     │ A1      │ a       │
 +│ 2   │ 2     │ B       │ missing │
 +│ 3   │ 3     │ C       │ missing │
 +│ 4   │ 1     │ A2      │ a       │
 +│ 5   │ 4     │ E1      │ d1      │
 +│ 6   │ 4     │ E1      │ d2      │
 +│ 7   │ 4     │ E2      │ d1      │
 +│ 8   │ 4     │ E2      │ d2      │
 +│ 9   │ 5     │ missing │ e1      │
 +│ 10  │ 5     │ missing │ e2      │
 +│ 11  │ 6     │ missing │ f       │
 +
 +julia> join( df1, df2, on= :id, kind= :anti )          ## from df1, not in df2
 +2×2 DataFrame
 +│ Row │ id    │ v1     │
 +│     │ Int64 │ String │
 +├─────┼───────┼────────┤
 +│ 1   │ 2     │ B      │
 +│ 2   │ 3     │ C      │
 +
 +
 +```
 +
 +
 +
 +
 +
 +# Backmatter
 +
 +## Useful Packages on Julia Repository
 +
 +* [Query.jl](https://​juliadata.github.io/​DataFrames.jl/​stable/​man/​querying_frameworks.html) ​ can filter, project, join, flatten, and group data.
 +
 +## Notes
 +
 +FIXME Give background and look into Query.jl (general; soon to add dplyr @select and @mutate), DataFramesMeta.jl (faster), JuliaDBMeta.jl,​ and SplitApplyCombine.jl ​ .  Disadvantage---not core supported. ​ if DataFrame changes, they may break if they are no longer supported. ​ So do not bet the farm on them.
 +
 +
 +## References
 +
 +https://​en.wikibooks.org/​wiki/​Introducing_Julia/​DataFrames
  
dataframecomplex.txt · Last modified: 2018/12/27 14:34 (external edit)