# Iterating over (key, value) with grouped DataFrame

**URL:** <https://discourse.julialang.org/t/iterating-over-key-value-with-grouped-dataframe/27360>\
**Category:** General Usage\
**Tags:** data, dataframes\
**Created:** [August 9, 2019, 7:37pm UTC](https://discourse.julialang.org/t/iterating-over-key-value-with-grouped-dataframe/27360 "2019-08-09T19:37:04Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![ElOceanografo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eloceanografo/32/624_2.png) [@ElOceanografo](https://discourse.julialang.org/u/ElOceanografo)\
**Post date:** [August 9, 2019, 7:37pm UTC](https://discourse.julialang.org/t/iterating-over-key-value-with-grouped-dataframe/27360/1 "2019-08-09T19:37:04Z")

</div>

Not sure if I’m being dense here, but is there a simple way to iterate over a GroupedDataFrame, having the grouping levels available at each iteration? i.e. something like

```julia
df = DataFrame(a = [1,1,2,2], b = randn(4))
gdf = groupby(df, :a)

for (keys, subdf) in iterator_im_looking_for(gdf)
    println((keys, subdf))
end
# Desired output: (NamedTuple, SubDataFrame) pairs, or something similar
#
#((a=1,), 2×2 SubDataFrame
#│ Row │ a │ b │
#│ │ Int64 │ Float64 │
#├─────┼───────┼──────────┤
#│ 1 │ 1 │ 0.109089 │
#│ 2 │ 1 │ 0.107033 │)
#((a=2,), 2×2 SubDataFrame
#│ Row │ a │ b │
#│ │ Int64 │ Float64 │
#├─────┼───────┼──────────┤
#│ 1 │ 2 │ 1.29613 │
#│ 2 │ 2 │ -2.33027 │)

```

---

<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:** [August 9, 2019, 7:52pm UTC](https://discourse.julialang.org/t/iterating-over-key-value-with-grouped-dataframe/27360/2 "2019-08-09T19:52:14Z")

</div>

Is this what you are looking for? [https://github.com/JuliaData/DataFrames.jl/pull/1908](https://github.com/JuliaData/DataFrames.jl/pull/1908).

Until that is released you can get grouping variables as a data frame using eg. `collect(x -> first(x)[groupvars(parent(x))], gdf)`

---

<div class="post-metadata">

**Author:** ![ElOceanografo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eloceanografo/32/624_2.png) [@ElOceanografo](https://discourse.julialang.org/u/ElOceanografo)\
**Post date:** [August 9, 2019, 8:14pm UTC](https://discourse.julialang.org/t/iterating-over-key-value-with-grouped-dataframe/27360/3 "2019-08-09T20:14:46Z")

</div>

Ha, that’s exactly what I’m looking for. Thanks!

---

<div class="post-metadata">

**Author:** ![ElOceanografo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eloceanografo/32/624_2.png) [@ElOceanografo](https://discourse.julialang.org/u/ElOceanografo)\
**Post date:** [August 9, 2019, 8:29pm UTC](https://discourse.julialang.org/t/iterating-over-key-value-with-grouped-dataframe/27360/4 "2019-08-09T20:29:48Z")

</div>

> [@bkamins](#):
>
> collect(x → first(x)[groupvars(parent(x))], gdf)

This code doesn’t work, but this does:

```julia
[parent(gdf)[i, groupvars(gdf)] for i in gdf.starts]

```

---

<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:** [August 9, 2019, 9:08pm UTC](https://discourse.julialang.org/t/iterating-over-key-value-with-grouped-dataframe/27360/5 "2019-08-09T21:08:37Z")

</div>

Sorry, I was writing from my head and mixed up `collect` with `combine`. This is what works as an example:

```julia
select!(combine(first, gdf), groupvars(gdf))

```

The solution from the linked PR using `gdf.starts` works, but it is using an internal, undocumented `starts` field that is not guaranteed to be supported in the future.

---

<div class="post-metadata">

**Author:** ![gobs](https://avatars.discourse-cdn.com/v4/letter/g/bc8723/32.png) [@gobs](https://discourse.julialang.org/u/gobs)\
**Post date:** [January 11, 2022, 10:38am UTC](https://discourse.julialang.org/t/iterating-over-key-value-with-grouped-dataframe/27360/6 "2022-01-11T10:38:55Z")

</div>

Re-opening this thread because this does not appear to work anymore. This does however:

```julia
for (k,v) in zip(first.(keys(gdf)), gdf)

```

Perhaps there is a better / more succinct way of doing this?

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [January 11, 2022, 11:53am UTC](https://discourse.julialang.org/t/iterating-over-key-value-with-grouped-dataframe/27360/7 "2022-01-11T11:53:44Z")

</div>

@gobs, perhaps like this:

```julia
for (k,v) in pairs(gdf)
    println(k, v)
end

```

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [January 11, 2022, 12:13pm UTC](https://discourse.julialang.org/t/iterating-over-key-value-with-grouped-dataframe/27360/8 "2022-01-11T12:13:31Z")

</div>

To elaborate on @rafael.guerra’s answer, you can also get the key value directly via destructuring:

```julia
for ((k,), v) in pairs(gdf)
    println(k => v)
end

```

or to get the key by name (with Julia 1.7):

```julia
for ((; a), v) in pairs(gdf)
    println(a => v)
end

```

The solution of @bkamins to get the list of keys and key values still works except that `groupvars` was renamed to `groupcols`:

```julia
julia> select!(combine(first, gdf), groupcols(gdf))
2×1 DataFrame
 Row │ a     
     │ Int64 
─────┼───────
   1 │ 1
   2 │ 2

```

but I think the modern way to do that is simply

```julia
julia> keys(gdf)
2-element DataFrames.GroupKeys{GroupedDataFrame{DataFrame}}:
 GroupKey: (a = 1,)
 GroupKey: (a = 2,)

```

and you can do something like `NamedTuple.(keys(gdf))` or `DataFrame(keys(gdf))` if you want a more convenient data structure.

---

<div class="post-metadata">

**Author:** ![phantom](https://avatars.discourse-cdn.com/v4/letter/p/e0b2c6/32.png) [@phantom](https://discourse.julialang.org/u/phantom)\
**Post date:** [October 18, 2022, 9:36pm UTC](https://discourse.julialang.org/t/iterating-over-key-value-with-grouped-dataframe/27360/9 "2022-10-18T21:36:14Z")

</div>

I think for a GroupDataFrame eachindex(gdf) also works.
