Combine(groupby())

Is there a way to do this:

c = combine(groupby(df, :A),:B => mean => :B_mean)

but in such a way that the output does not only show :A and :B_mean but also the other variables that df had (well, at least the variables that can also be combined due to repetition)?

DataFrames can’t know your intent beyond what you program. It can’t intuit which variables are invariant withing an β€œA” grouping unless you program that.

You could write:

vars_sub = Symbol.(setdiff(names(df), ["B", "A"]) )
c = combine(groupby(df, :A), :B => mean => :B_mean, (vars_sub .=> first )...) 

You can just add all the variables that are constant within groups as extra grouping variables.

julia> using Statistics, StatsBase

julia> df = DataFrame(A = [1, 1, 2, 2], B = [1, 2, 300, 400], C = [5, 5, 6, 6], D = [10, 30, 60, 80])
4Γ—4 DataFrame
 Row β”‚ A      B      C      D     
     β”‚ Int64  Int64  Int64  Int64 
─────┼────────────────────────────
   1 β”‚     1      1      5     10
   2 β”‚     1      2      5     30
   3 β”‚     2    300      6     60
   4 β”‚     2    400      6     80

julia> function only_constant(x)
           all(==(first(x)), x) || throw(ArgumentError("All elements of the vector must be equal"))
           return first(x)
       end;

julia> @chain df begin
           @by :A begin
               :B = mean(:B)
               $([:C] .=> only_constant)
           end
       end
2Γ—3 DataFrame
 Row β”‚ A      B        C_only_constant 
     β”‚ Int64  Float64  Int64           
─────┼─────────────────────────────────
   1 β”‚     1      1.5                5
   2 β”‚     2    350.0                6

Thanks for the great answers. I wonder whether there could be a shortcut for this. It’s probably not so rare that you have not only multiple factors and levels, but also multiple observations per subject and you want to group by ID and e.g. average some result.

A variant of @croberts’ code:

gdf = groupby(df, :A)
combine(gdf, :B => mean => :B_mean, Not([:A, :B]) .=> first)

@rafael.guerra ’s solution is the easiest to parse for newbies, but still bit hard to remember.

In plain English, it reads: For each column in the grouped dataframe (gdf), excluding the grouping variable (:A) and the aggregated column (:B), take the first value within each group.