我有一个简单的数据框架如下所示:

import polars as pl

df = pl.DataFrame(
    {
        "group": [1, 1, 1, 1, 2, 2, 2, 2],
        "a": [1, 2, 3, 4, 1, 2, 3, 4],
        "b": [5, 1, 7, 9, 2, 4, 9, 7],
        "c": [2, 6, 3, 9, 1, 5, 3, 6],
    }
)

我希望在极点数据框中有一个相关的‘矩阵’, struct 如下.我怎么能做到这一点?

┌───────┬──────┬──────────┬──────────┬──────────┐
│ group ┆ name ┆ a        ┆ b        ┆ c        │
│ ---   ┆ ---  ┆ ---      ┆ ---      ┆ ---      │
│ i64   ┆ str  ┆ f64      ┆ f64      ┆ f64      │
╞═══════╪══════╪══════════╪══════════╪══════════╡
│ 1     ┆ a    ┆ 1.0      ┆ 0.680336 ┆ 0.734847 │
│ 1     ┆ b    ┆ 0.680336 ┆ 1.0      ┆ 0.246885 │
│ 1     ┆ c    ┆ 0.734847 ┆ 0.246885 ┆ 1.0      │
│ 2     ┆ a    ┆ 1.0      ┆ 0.830455 ┆ 0.756889 │
│ 2     ┆ b    ┆ 0.830455 ┆ 1.0      ┆ 0.410983 │
│ 2     ┆ c    ┆ 0.756889 ┆ 0.410983 ┆ 1.0      │
└───────┴──────┴──────────┴──────────┴──────────┘

目前,我是这样try 的:

df.groupby("group").agg(
    [
        pl.corr(col1, col2).alias(f"{col1}_{col2}")
        for col1 in ["a", "b", "c"]
        for col2 in ["a", "b", "c"]
    ]
)

shape: (2, 10)
┌───────┬─────┬──────────┬──────────┬─────┬──────────┬──────────┬──────────┬─────┐
│ group ┆ a_a ┆ a_b      ┆ a_c      ┆ ... ┆ b_c      ┆ c_a      ┆ c_b      ┆ c_c │
│ ---   ┆ --- ┆ ---      ┆ ---      ┆     ┆ ---      ┆ ---      ┆ ---      ┆ --- │
│ i64   ┆ f64 ┆ f64      ┆ f64      ┆     ┆ f64      ┆ f64      ┆ f64      ┆ f64 │
╞═══════╪═════╪══════════╪══════════╪═════╪══════════╪══════════╪══════════╪═════╡
│ 2     ┆ 1.0 ┆ 0.830455 ┆ 0.756889 ┆ ... ┆ 0.410983 ┆ 0.756889 ┆ 0.410983 ┆ 1.0 │
│ 1     ┆ 1.0 ┆ 0.680336 ┆ 0.734847 ┆ ... ┆ 0.246885 ┆ 0.734847 ┆ 0.246885 ┆ 1.0 │
└───────┴─────┴──────────┴──────────┴─────┴──────────┴──────────┴──────────┴─────┘

因此,我不确定如何才能将其转换为我想要的形状/ struct ?或者,有没有其他(可能更好的)方法来直接生成我想要的结果?

推荐答案

@jqury,这里有一种方法,它在DataFrame本身上使用corr函数.

(
    pl.concat(
        next_df
        .select(pl.exclude('group'))
        .corr()
        .select([
            pl.lit(next_group).alias('group'),
            pl.Series(next_df.columns[1:]).alias('name'),
            pl.all()
        ])
        for next_group, next_df
        in df.partition_by('group', as_dict=True).items()
    )
)
shape: (6, 5)
┌───────┬──────┬──────────┬──────────┬──────────┐
│ group ┆ name ┆ a        ┆ b        ┆ c        │
│ ---   ┆ ---  ┆ ---      ┆ ---      ┆ ---      │
│ i32   ┆ str  ┆ f64      ┆ f64      ┆ f64      │
╞═══════╪══════╪══════════╪══════════╪══════════╡
│ 1     ┆ a    ┆ 1.0      ┆ 0.680336 ┆ 0.734847 │
│ 1     ┆ b    ┆ 0.680336 ┆ 1.0      ┆ 0.246885 │
│ 1     ┆ c    ┆ 0.734847 ┆ 0.246885 ┆ 1.0      │
│ 2     ┆ a    ┆ 1.0      ┆ 0.830455 ┆ 0.756889 │
│ 2     ┆ b    ┆ 0.830455 ┆ 1.0      ┆ 0.410983 │
│ 2     ┆ c    ┆ 0.756889 ┆ 0.410983 ┆ 1.0      │
└───────┴──────┴──────────┴──────────┴──────────┘

Performance

它的表现如何?让我们分成1,000组,每组观察100,000次:

import numpy as np
import time

nbr_groups = 1_000
nbr_obs_per_group = 100_000

rng = np.random.default_rng(1)
df = pl.DataFrame({
    'group': list(range(0, nbr_groups)) * nbr_obs_per_group,
    **{col_nm: rng.normal(0, 1, nbr_obs_per_group * nbr_groups)
       for col_nm in ['a', 'b', 'c']
       }
})
df
shape: (100000000, 4)
┌───────┬───────────┬───────────┬───────────┐
│ group ┆ a         ┆ b         ┆ c         │
│ ---   ┆ ---       ┆ ---       ┆ ---       │
│ i64   ┆ f64       ┆ f64       ┆ f64       │
╞═══════╪═══════════╪═══════════╪═══════════╡
│ 0     ┆ 0.345584  ┆ -0.858613 ┆ 1.382227  │
│ 1     ┆ 0.821618  ┆ 0.965737  ┆ 1.086405  │
│ 2     ┆ 0.330437  ┆ -0.567488 ┆ 0.57299   │
│ 3     ┆ -1.303157 ┆ 1.070117  ┆ 0.147326  │
│ …     ┆ …         ┆ …         ┆ …         │
│ 996   ┆ 0.842205  ┆ 0.515653  ┆ 0.88825   │
│ 997   ┆ -0.133607 ┆ -1.1532   ┆ -1.041619 │
│ 998   ┆ -0.256237 ┆ 0.654807  ┆ -0.852552 │
│ 999   ┆ -0.627053 ┆ -0.133583 ┆ 0.531616  │
└───────┴───────────┴───────────┴───────────┘
start = time.perf_counter()
(
    pl.concat(
        next_df
        .select(pl.exclude('group'))
        .corr()
        .select([
            pl.lit(next_group).alias('group'),
            pl.Series(next_df.columns[1:]).alias('name'),
            pl.all()
        ])
        for next_group, next_df
        in df.partition_by('group', as_dict=True).items()
    )
)
print(time.perf_counter() - start)
shape: (3000, 5)
┌───────┬──────┬───────────┬───────────┬───────────┐
│ group ┆ name ┆ a         ┆ b         ┆ c         │
│ ---   ┆ ---  ┆ ---       ┆ ---       ┆ ---       │
│ i32   ┆ str  ┆ f64       ┆ f64       ┆ f64       │
╞═══════╪══════╪═══════════╪═══════════╪═══════════╡
│ 0     ┆ a    ┆ 1.0       ┆ 0.002105  ┆ 0.006153  │
│ 0     ┆ b    ┆ 0.002105  ┆ 1.0       ┆ -0.001446 │
│ 0     ┆ c    ┆ 0.006153  ┆ -0.001446 ┆ 1.0       │
│ 1     ┆ a    ┆ 1.0       ┆ -0.00137  ┆ -0.003253 │
│ …     ┆ …    ┆ …         ┆ …         ┆ …         │
│ 998   ┆ c    ┆ 0.002755  ┆ 0.001199  ┆ 1.0       │
│ 999   ┆ a    ┆ 1.0       ┆ -0.001362 ┆ -0.000156 │
│ 999   ┆ b    ┆ -0.001362 ┆ 1.0       ┆ -0.00049  │
│ 999   ┆ c    ┆ -0.000156 ┆ -0.00049  ┆ 1.0       │
└───────┴──────┴───────────┴───────────┴───────────┘
>>> print(time.perf_counter() - start)
6.240678512999693

在我的32核系统上,对于一个有1亿条记录的DataFrame,大约6秒.可能有更快的算法,但代码相对简单.

Python相关问答推荐

Telethon加入私有频道

在极性中创建条件累积和

多处理队列在与Forking http.server一起使用时随机跳过项目

如何使用Numpy. stracards重新编写滚动和?

LocaleError:模块keras._' tf_keras. keras没有属性__internal_'''

为什么常规操作不以其就地对应操作为基础?

ModuleNotFoundError:没有模块名为x时try 运行我的代码''

如何过滤组s最大和最小行使用`transform`'

在电影中向西北方向对齐""

如何在Python中将超链接添加到PDF中每个页面的顶部?

如何在信号的FFT中获得正确的频率幅值

如何在Python中从html页面中提取html链接?

我可以同时更改多个图像吗?

如何使用count()获取特定日期之间的项目

GEKKO中若干参数的线性插值动态优化

IpyWidget Select 框未打开

这是什么排序算法?(将迭代器与自身合并&&Q;)

判断字典键、值对是否满足用户定义的搜索条件

在忽略on列中的重复值的同时连接polars重命名

达到最大的Python Webhost资源