# How to get the first row of each group of a DataFrame?

**URL:** <https://discourse.julialang.org/t/how-to-get-the-first-row-of-each-group-of-a-dataframe/47320>\
**Category:** New to Julia\
**Created:** [September 26, 2020, 3:28pm UTC](https://discourse.julialang.org/t/how-to-get-the-first-row-of-each-group-of-a-dataframe/47320 "2020-09-26T15:28:18Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![tp2750](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tp2750/32/207806_2.png) [@tp2750](https://discourse.julialang.org/u/tp2750)\
**Post date:** [September 26, 2020, 3:28pm UTC](https://discourse.julialang.org/t/how-to-get-the-first-row-of-each-group-of-a-dataframe/47320/1 "2020-09-26T15:28:18Z")

</div>

How do I get the first row from each group of a grouped DataFrame?

Say, I want to find the sex and height of the tallest person in each age-group:

```julia
using DataFrames
df = DataFrame(sex = repeat(["F","M"], inner=4, outer=2), age = repeat(14:2:20,outer=4), height=100 .+100 .*rand(16))
16×3 DataFrame
│ Row │ sex │ age │ height │
│ │ String │ Int64 │ Float64 │
├─────┼────────┼───────┼─────────┤
│ 1 │ F │ 14 │ 127.878 │
│ 2 │ F │ 16 │ 133.063 │
│ 3 │ F │ 18 │ 186.6 │
│ 4 │ F │ 20 │ 133.589 │
│ 5 │ M │ 14 │ 186.655 │
│ 6 │ M │ 16 │ 144.436 │
│ 7 │ M │ 18 │ 155.293 │
│ 8 │ M │ 20 │ 181.719 │
│ 9 │ F │ 14 │ 199.308 │
│ 10 │ F │ 16 │ 114.783 │
│ 11 │ F │ 18 │ 111.551 │
│ 12 │ F │ 20 │ 121.64 │
│ 13 │ M │ 14 │ 177.85 │
│ 14 │ M │ 16 │ 170.868 │
│ 15 │ M │ 18 │ 126.169 │
│ 16 │ M │ 20 │ 125.229 │

```

I tried this:

```julia
sort!(df, :height, rev=true)
first(groupby(df, :age))
4×3 SubDataFrame
│ Row │ sex │ age │ height │
│ │ String │ Int64 │ Float64 │
├─────┼────────┼───────┼─────────┤
│ 1 │ F │ 14 │ 199.308 │
│ 2 │ M │ 14 │ 186.655 │
│ 3 │ M │ 14 │ 177.85 │
│ 4 │ F │ 14 │ 127.878 │

```

But this gives me the first group, not the first row from each group.

Then my instinct would be to “dot the `first`”, but then I get:

```julia
first.(groupby(df, :age))
ERROR: ArgumentError: broadcasting over `GroupedDataFrame`s is reserved

```

In R I would do:

```julia
df <- data.frame(sex = rep(c("F","M"),2, each =4), age=rep(seq(14,20,2),4), height = 100 + 100*runif(16))
df <- plyr::arrange(df, plyr::desc(height))
plyr::ddply(df, ~ age, head, 1)
  sex age height
1 M 14 193.4705
2 F 16 199.1906
3 M 18 165.1674
4 F 20 177.7445

```

What is the idiomatic way in DataFrames?

---

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [September 26, 2020, 3:36pm UTC](https://discourse.julialang.org/t/how-to-get-the-first-row-of-each-group-of-a-dataframe/47320/2 "2020-09-26T15:36:15Z")

</div>

Here are three options to get it:

```julia
julia> combine(groupby(df, :age)) do sdf
       sdf[argmax(sdf.height), :]
       end
4×3 DataFrame
│ Row │ age │ sex │ height │
│ │ Int64 │ String │ Float64 │
├─────┼───────┼────────┼─────────┤
│ 1 │ 14 │ M │ 179.193 │
│ 2 │ 16 │ M │ 188.043 │
│ 3 │ 18 │ F │ 181.994 │
│ 4 │ 20 │ M │ 171.729 │

julia> combine(groupby(df, :age)) do sdf
       first(sort(sdf, :height, rev=true))
       end
4×3 DataFrame
│ Row │ age │ sex │ height │
│ │ Int64 │ String │ Float64 │
├─────┼───────┼────────┼─────────┤
│ 1 │ 14 │ M │ 179.193 │
│ 2 │ 16 │ M │ 188.043 │
│ 3 │ 18 │ F │ 181.994 │
│ 4 │ 20 │ M │ 171.729 │

julia> combine(first, groupby(sort(df, :height, rev=true), :age))
4×3 DataFrame
│ Row │ age │ sex │ height │
│ │ Int64 │ String │ Float64 │
├─────┼───────┼────────┼─────────┤
│ 1 │ 16 │ M │ 188.043 │
│ 2 │ 18 │ F │ 181.994 │
│ 3 │ 14 │ M │ 179.193 │
│ 4 │ 20 │ M │ 171.729 │

```

(the first one is fastest as it does not require sorting)

---

<div class="post-metadata">

**Author:** ![tp2750](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tp2750/32/207806_2.png) [@tp2750](https://discourse.julialang.org/u/tp2750)\
**Post date:** [September 26, 2020, 3:42pm UTC](https://discourse.julialang.org/t/how-to-get-the-first-row-of-each-group-of-a-dataframe/47320/3 "2020-09-26T15:42:37Z")

</div>

Wow that was quick!

Thank you so much @bkamins.  
And thank you for DataFrames in general 😄 This is a great package 👍

---

<div class="post-metadata">

**Author:** ![tp2750](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tp2750/32/207806_2.png) [@tp2750](https://discourse.julialang.org/u/tp2750)\
**Post date:** [September 26, 2020, 4:02pm UTC](https://discourse.julialang.org/t/how-to-get-the-first-row-of-each-group-of-a-dataframe/47320/4 "2020-09-26T16:02:22Z")

</div>

The last solution is closest to my expectation:

```julia
combine(first, groupby(df, :age))
4×3 DataFrame
│ Row │ age │ sex │ height │
│ │ Int64 │ String │ Float64 │
├─────┼───────┼────────┼─────────┤
│ 1 │ 14 │ F │ 199.308 │
│ 2 │ 18 │ F │ 186.6 │
│ 3 │ 20 │ M │ 181.719 │
│ 4 │ 16 │ M │ 170.868 │

```

But the first two preserve the order of the age groups.

Thanks again!

---

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [September 26, 2020, 5:56pm UTC](https://discourse.julialang.org/t/how-to-get-the-first-row-of-each-group-of-a-dataframe/47320/5 "2020-09-26T17:56:32Z")

</div>

> [@tp2750](#):
>
> But the first two preserve the order of the age groups.

Exactly. Note that you can also pass `sort` to `groupby` if you want groups to be sorted.

---

<div class="post-metadata">

**Author:** ![Rahul](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rahul/32/30545_2.png) [@Rahul](https://discourse.julialang.org/u/Rahul)\
**Post date:** [December 20, 2022, 12:54am UTC](https://discourse.julialang.org/t/how-to-get-the-first-row-of-each-group-of-a-dataframe/47320/6 "2022-12-20T00:54:59Z")

</div>

Is there a way to do the last one in DataFramesMeta using `groupby` and `@combine` ?

---

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [December 20, 2022, 12:23pm UTC](https://discourse.julialang.org/t/how-to-get-the-first-row-of-each-group-of-a-dataframe/47320/7 "2022-12-20T12:23:01Z")

</div>

> [@tp2750](#):
>
> `combine(first, groupby(df, :age))`

You mean this one?

```julia
@chain df begin
    groupby :age
    @combine $first
end

```

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [December 20, 2022, 4:58pm UTC](https://discourse.julialang.org/t/how-to-get-the-first-row-of-each-group-of-a-dataframe/47320/8 "2022-12-20T16:58:55Z")

</div>

if the constraint on the use of combine is removed, a new (among others) possibility

```julia
gdf=groupby(df,:age)
subset(gdf, :height => x->x.== maximum(x))

```

PS  
The “advantage” of this solution compared to the others with the use of `combine` is the management of the presence of any “homozygous twins” (therefore having the same height for genetic reasons). 😀
