按 Julia 中列中值的顺序出现对 DataFrame 进行分组

Group DataFrame by sequential occurrence of values in a column in Julia

假设我有以下 DataFrame:

julia> Random.seed!(1)
TaskLocalRNG()

julia> df = DataFrame(data = rand(1:10, 10), gr = rand([0, 1], 10))
10×2 DataFrame
 Row │ data   gr    
     │ Int64  Int64 
─────┼──────────────
   1 │     1      1
   2 │     4      0
   3 │     7      0
   4 │     7      0
   5 │    10      1
   6 │     2      1
   7 │     8      0
   8 │     8      0
   9 │     7      0
  10 │     2      0

我想要的不仅仅是:gr的值,还有这些值的出现次数。在这种情况下,组数应为 4:

Group 1 (1 row)
 Row │ data   gr    
     │ Int64  Int64 
─────┼──────────────
   1 │     1      1


Group 2 (3 rows)
 Row │ data   gr    
     │ Int64  Int64 
─────┼──────────────
   2 │     4      0
   3 │     7      0
   4 │     7      0

Group 3 (2 rows)
 Row │ data   gr    
     │ Int64  Int64 
─────┼──────────────
   5 │    10      1
   6 │     2      1

Group 4 (4 rows)
 Row │ data   gr    
     │ Int64  Int64 
─────┼──────────────
   7 │     8      0
   8 │     8      0
   9 │     7      0
  10 │     2      0

但是,如果我按 :gr 列分组,我只能得到两组:

julia> groupby(df, :gr)
GroupedDataFrame with 2 groups based on key: gr
First Group (7 rows): gr = 0
 Row │ data   gr    
     │ Int64  Int64 
─────┼──────────────
   1 │     4      0
   2 │     7      0
   3 │     7      0
   4 │     8      0
   5 │     8      0
   6 │     7      0
   7 │     2      0
⋮
Last Group (3 rows): gr = 1
 Row │ data   gr    
     │ Int64  Int64 
─────┼──────────────
   1 │     1      1
   2 │    10      1
   3 │     2      1

我如何在 Julia DataFrames.jl 中实现它?谢谢

versioninfo()
Julia Version 1.7.1
Commit ac5cc99908 (2021-12-22 19:35 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin19.5.0)
  CPU: Apple M1 Max
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-12.0.1 (ORCJIT, westmere)
Environment:
  JULIA_NUM_THREADS = 1
  JULIA_EDITOR = code

您可以按每次 :gr 更改值时递增的新变量分组。

例如:

nrow = size(df,1)
gr1 = zeros(Int64, nrow)
for i=2:nrow
gr1[i] = gr1[i-1] + (df.gr[i] != df.gr[i-1])
end
df.gr1 = gr1

与@GEK 的答案相同的基本思想,具有更向量化的实现:

julia> edgedetect(col) = [0; abs.(diff(col))] |> cumsum
edgedetect (generic function with 1 method)

julia> edgedetect([0, 1, 1, 1, 0, 0, 1]) |> print 
[0, 1, 1, 1, 2, 2, 3]

abs.(diff(col)) 在列 col 的值发生变化的地方放置 1,在其他地方放置 0。 (diff returns n-1 差异给定 n 个元素,因此我们在结果前加上 0 以保持列长度。)对此进行累加和,我们得到一个新列,每次增加原始列中的值发生变化。

然后我们可以在转换后的数据帧上使用此函数 groupby,如下所示:

julia> groupby(transform(df, :gr => edgedetect => :gr_edges, copycols = false), :gr_edges) |> print
GroupedDataFrame with 4 groups based on key: gr_edges
Group 1 (1 row): gr_edges = 0
 Row │ data   gr     gr_edges 
     │ Int64  Int64  Int64    
─────┼────────────────────────
   1 │     1      1         0
Group 2 (3 rows): gr_edges = 1
 Row │ data   gr     gr_edges 
     │ Int64  Int64  Int64    
─────┼────────────────────────
   1 │     4      0         1
   2 │     7      0         1
   3 │     7      0         1
Group 3 (2 rows): gr_edges = 2
 Row │ data   gr     gr_edges 
     │ Int64  Int64  Int64    
─────┼────────────────────────
   1 │    10      1         2
   2 │     2      1         2
Group 4 (4 rows): gr_edges = 3
 Row │ data   gr     gr_edges 
     │ Int64  Int64  Int64    
─────┼────────────────────────
   1 │     8      0         3
   2 │     8      0         3
   3 │     7      0         3
   4 │     2      0         3