【问题标题】:DataFrame with correlation between several columns based on grouping column基于分组列的多列之间具有相关性的DataFrame
【发布时间】:2020-10-13 03:45:22
【问题描述】:

我有一个具有以下结构的数据框:

|file_id|metric_a|metric_b|metric_c|
|'1.xml'| 1      | 0.5    | 50     |
|'1.xml'| 1.5    | 0.55   | 65     | 
|'2.xml'| 2      | 0.7    | 75     |
|'2.xml'| 2.5    | 0.75   | 80     | 

因此,我想得到这张“metric_c”和其他列之间的相关表:

|file_id|correlation_a_c|correlation_b_c|
|'1.xml'| 0.7           |  0.8          |
|'2.xml'| 0.75          |  0.85         | 

我用下面的代码来做,但看起来很糟糕:

metric_a_vs_metric_c_df = source_df.groupby('file_id')[
                                  ['metric_a', 'metric_c']].corr(method='spearman').iloc[0::2,-1].reset_index().rename(
    columns={'metric_a': 'correlation_a_c'}
)
metric_b_vs_metric_c_df = source_df.groupby('file_id')[
                                 ['metric_b', 'metric_c']].corr(method='spearman').iloc[0::2,-1].reset_index().rename(
    columns={'metric_b': 'correlation_b_c'}
)
joined_df = metric_a_vs_metric_c_df.set_index('file_id').join(metric_b_vs_metric_c_df.set_index('file_id'), lsuffix='_caller', rsuffix='_other')
print(joined_df)

是否存在使其更具可读性的方法?

【问题讨论】:

  • 能否添加一些示例数据?
  • 还有,预期的输出是什么?
  • 在您的输入中,每个文件 ID 都有一个条目。为什么需要 groupby?此外,通常在两个数字系列之间计算相关性 - 而不是在单个元素之间 (AFAIK)。
  • 只是一个实用的提示,以避免你的变量名有半英里长:你试图计算的是一个 crosstab,或简称xt。因此,一个不错的名称选择是xt_acxt_bc。或corrxt_ac, corrxt_bc 缩写为“相关交叉表”。这将有助于将您的行保持在 72-80 个字符以下的行长和可读性。我们不需要到处说metric_...。 (我个人会将第一个数据框中的三个变量列重命名为 a, b,c
  • @Roy2012 是的,你是对的,我的行具有相同的 file_id 和不同的指标,这就是为什么我在我的代码示例中按文件 id 分组并在分组后找到相关性,

标签: python pandas dataframe correlation crosstab


【解决方案1】:

你可以使用crosstab它返回一个DataFrame,然后在上面应用correlation

metric_a_vs_metric_c_df = pd.crosstab(df['metric_a'],df['metric_c'])
【解决方案2】:

这里有一个解决方案。由于样本数据是幼稚的,因此结果也是幼稚的 - 但它也适用于真实数据。

df = df.groupby("file_id").corr().reset_index().melt(id_vars = ["file_id", "level_1"])
ac = df[(df.level_1 == "metric_a") & (df.variable == "metric_c")]
bc = df[(df.level_1 == "metric_b") & (df.variable == "metric_c")]
df = pd.concat([ac, bc])
df["metrics"] = df.level_1 + "_" + df.variable

df = pd.pivot_table(df, index="file_id", columns="metrics")
df.columns = [c[1] for c in df.columns]

结果是:

         metric_a_metric_c  metric_b_metric_c
file_id                                      
'1.xml'                1.0                1.0
'2.xml'                1.0                1.0

【讨论】:

  • 我检查了crosstab。看起来它是成对工作的。您更好地了解问题并提出相关问题。我会等一段时间,但我认为你的答案是一个实际上接近预期行为的答案
  • 让 df 不是数据透视表会更舒服。我正在处理它:` res = (pd.pivot_table(df, index="file_id", columns="metrics")) flattened = pd.DataFrame(res.to_records()) flattened.columns = [hdr.replace ("('value', ", "").replace(")", "") for hdr in flattened.columns]`
  • 只是为了让我理解 - 您想要一个简单的数据框作为最终结果,而不是包含多索引列的数据透视表?如果这就是您正在寻找的,我在解决方案中添加了几行来做到这一点。
  • 在您将数据透视到 df 'fle_id' 的方法中,并未将其视为列。我添加到评论中的代码实际上符合我的计划
【解决方案3】:

您想分别计算列 'a'-'c'、'b'-'c' 之间的 (Spearman) 相关性的crosstab。 这是带有crosstab 的单行代码,它允许您传递自定义聚合函数。比如:

df[['a']].apply(lambda s: df['c'].corr('spearman',s.values), axis=1)

# (this is nearly working, you get the idea)

这是从 PSV 读取数据帧的样板(管道分隔值,即分隔符是“|”),并在列名中替换“metric_”->“”。

import pandas as pd
from io import StringIO

df = """|file_id|metric_a|metric_b|metric_c|
|'1.xml'| 1      | 0.5    | 50     |
|'2.xml'| 2      | 0.7    | 75     |"""

df = pd.read_csv(StringIO(df), sep='|', index_col=[0], usecols=[1,2,3,4])

df.columns = [s.replace('metric_', '') for s in df.columns]

顺便说一句,pandas 数据帧也有一个 corr 函数,它计算所有列相关性:

>>> df.corr(method='spearman')
     a    b    c
a  1.0  1.0  1.0
b  1.0  1.0  1.0
c  1.0  1.0  1.0

【讨论】:

  • 我需要根据每个 field_id 的分组来计算相关性。我不能在数据框上只使用corr。我添加了具有重复文件名和不同指标值的数据样本。
  • 这就是顶部df[['a']].apply(lambda s: df['c'].corr('spearman',s.values), axis=1) 的命令正在执行的操作。 (我只提到了另一个更通用的df.corr() 作为脚注)。而且您实际上不需要明确的groupby('field_id'),AFAIK
猜你喜欢
  • 1970-01-01
  • 2019-03-09
  • 1970-01-01
  • 2017-01-11
  • 2015-05-10
  • 2021-05-19
  • 1970-01-01
  • 2021-11-14
  • 2019-01-22
相关资源
最近更新 更多