为ggplot/rpy2处理独特索引的pandas数据框的重塑

3 投票
2 回答
1457 浏览
提问于 2025-04-17 17:14

这个问题和在Python的pandas中对数据框进行拆分和合并,以便使用rpy2进行绘图有关。我正在处理pandas数据框,并进行各种“融化”(melting)和“解融”(unmelting)操作,以便能够用ggplot2进行绘图。我对如何在具有唯一索引的数据框上执行这些操作有点困惑。假设数据框df有一个唯一的列runner_id,它记录了每个跑步者在两场比赛(比赛AB)中完成的时间和速度。每个跑步者都是独一无二的,因此数据框对于两个跑步者bobmary可以是这样的:

df = pandas.DataFrame([{"runner_id": "bob", "time_A": 30,
                        "time_B": 25, "speed_A": 5, "speed_B": 10},
                       {"runner_id": "mary", "time_A": 29,
                        "time_B": 19, "speed_A": 8, "speed_B": 12}])

df看起来是这样的:

  runner_id  speed_A  speed_B  time_A  time_B
0       bob        5       10      30      25
1      mary        8       12      29      19

由于跑步者是独特的,因此用runner_id来索引数据框非常方便。这也可以防止意外添加重复的条目,因为我们知道每个跑步者的信息应该保留在该跑步者的行中,不能有多个行对应同一个跑步者:

df = df.set_index("runner_id")

问题是,如果我们想要绘制两场比赛之间的时间或速度差异,ggplot需要使用列名time_A, time_B, speed_A, speed_B中的信息。那么df就需要看起来像这样:

runner_id  race  time  speed 
bob        A     ...   ...
mary       A     
bob        B
mary       B

这样我们就可以进行:

ggplot2.ggplot(df) + \
ggplot2.geom_point(aes_string(x="time", y="speed", colour="race")) ...

虽然这违反了runner_id条目的唯一性,因为跑步者需要被重复。一般来说,应该如何处理这个问题?有没有一种好的方式来保持df,既能保持唯一索引,又能方便ggplot的融化表示?我发现在这两者之间来回转换非常困难和混乱。第一种表示方式是每场比赛有不同的时间/速度列,并以跑步者为索引,这种方式非常直观,而ggplot的融化表示则令人困惑,似乎有些浪费。

关于在这两者之间转换的任何想法,或者关于如何保持数据框的一般规则都会很有帮助。在使用ggplot时,答案是否是不进行索引(不调用set_index)?对于这种类型的数据框,有没有推荐的格式?

一个潜在的解决方案是在进行解融/融化时始终对df进行索引/取消索引,比如:

melted_df = pandas.melt(df.reset_index(), id_vars="runner_id")

但这似乎容易出错。例如,如果我想计算每个跑步者在A比赛中的速度和时间的平均值,我可以尝试输出A的条目:

# This is already complicated
a_entries = melted_df[map(lambda x: x.endswith("_A"), melted_df["variable"])]

我现在有了冗余的/融化的表示,所以很难进行不重复计算跑步者的操作,因为每个跑步者现在出现了两次:

  runner_id variable  value
0       bob  speed_A      5
1      mary  speed_A      8
4       bob   time_A     30
5      mary   time_A     29

2 个回答

0

这是对一个长问题的简短而迟来的回答:看起来你需要一些帮助来理解长格式的数据框。每个值都是独一无二的,因为每场比赛中只有一个特定名字的“跑者”。刚开始接触的时候可能会让你感到困惑,但这实际上非常强大,并且对于充分利用ggplot2的功能来说是必不可少的。Hadley Wickham在几篇文章中对此解释得很好,比如这篇:http://had.co.nz/reshape/paper-dsc2005.pdf

1

在R语言中,融化和铸造数据框是一个常见的操作。Hadley开发的reshape包(还有reshape2,原来的melt()函数就在这里)之所以受欢迎,是有原因的。

使用ggplot2,你还可以以层的方式将数据添加到图表中。以你的例子为例:

import rpy2.robjects.pandas2ri
rpy2.robjects.pandas2ri.activate()

p = ggplot2.ggplot(rpy2.robjects.conversion.py2ri(df)) + \
    ggplot2.geom_point(ggplot2.aes_string(x="time_A",y="speed_A"),colour="#ff0000") + \
    ggplot2.geom_point(ggplot2.aes_string(x="time_B",y="speed_B"),colour="#0000ff") + \
    ggplot2.scale_x_continuous("time") + \
    ggplot2.scale_y_continuous("speed")
p.plot()

撰写回答