在Python中使用Rpy2改变ggplot2的因子顺序

1 投票
1 回答
1036 浏览
提问于 2025-04-17 18:16

我正在尝试把以下代码转换成Rpy2,但一直没有成功:

neworder <- c("virginica","setosa","versicolor")
library("plyr")
iris2 <- arrange(transform(iris,
             Species=factor(Species,levels=neworder)),Species)

这个代码的目的是改变某一列的factor顺序,这里指的是Species这一列。

我不想在Rpy2中使用plyr等工具,因为我可以直接修改作为Python对象绘制的数据框。以下代码没有效果:

# start with Python df 'mydf' and convert to R df
# to get mydf_r. The column equivalent of Species here
# is "variable"
# ...
mydf_r.variable = r.factor(ro.StrVector(["a", "b", "c"]))
# call ggplot...
ggplot2.ggplot(mydf) + ...

这段代码不管用。我该如何得到与R代码等效的结果呢?也就是说,我有一个“融化”的数据框,其中有多个variable的值被绘制为c, b, a,我想把顺序改成a, b, c,通过改变variablefactor顺序。谢谢。

编辑 我用以下代码成功改变了顺序:

labels = robj.StrVector(tuple(["a", "b", "c"]))
variable_factor = r.factor(labels, levels=labels)
r_melted = r.transform(r_melted, **{"variable": variable_factor})
p = ggplot2.ggplot(r_melted) + \
    ggplot2.geom_boxplot(aes_string(**{"x": "variable",
                                       "y": "value"
                                        "fill": "group"})) + \
    ggplot2.scale_fill_manual(values=np.array(["#00BA38", "#F8766D"])) + \
    ggplot2.coord_flip()

不过,这样做会破坏ggplot正确生成箱线图并根据group变量进行着色的能力。如果我去掉以下几行:

labels = robj.StrVector(tuple(["a", "b", "c"]))
variable_factor = r.factor(labels, levels=labels)
r_melted = r.transform(r_melted, **{"variable": variable_factor})

那么一切就正常了……我只想改变variable值在箱线图中出现的顺序。

@lgautier:你给的解决方案看起来符合我的需求,但在这里对我不起作用。我用iris数据集做了一个测试:

原始图

import os
iris = pandas.read_table(os.path.expanduser("~/iris.csv"),
                         sep=",")
iris["Species"] = iris["Name"]
r_melted = conversion_pydataframe(iris)
p = ggplot2.ggplot(r_melted) + \
    ggplot2.geom_boxplot(aes_string(**{"x": "PetalLength",
                                       "y": "PetalWidth",
                                       "fill": "Species"})) + \
    ggplot2.facet_grid(Formula("Species ~ .")) + \
    ggplot2.coord_flip()
p.plot()

生成的结果是:

enter image description here

但如果我在绘图之前添加:

labels = robj.StrVector(tuple(["versicolor", "virginica", "setosa"]))
variable_i = r_melted.names.index("Species")
r_melted[variable_i] = robj.FactorVector(r_melted[variable_i],
                                         levels=labels)

我得到的结果是:

enter image description here

我觉得这是因为我使用的名称与Species的名称值不完全匹配。如果出现这种情况,rpy2能否给出错误提示会很有帮助。不过无论如何,如果我想覆盖factor的名称该怎么办?也就是说,把第一个factor名称改成x,第二个改成y,等等,并按这个顺序显示?唯一的方法是为数据框创建一个新列,并在其中使用正确的名称吗?

1 个回答

2

你需要改变使用的因子的级别,可以在运行时直接修改(下面的第一个例子),或者在数据框的列中进行修改(第二个例子)。

如果 labels 是一个相对较短的列表,下面的代码就可以直接使用:

# r_melted is the one defined upstream of your code snippet,
# not the results of calling r.transform()
labels = robj.StrVector(tuple(["a", "b", "c"]))
p = ggplot2.ggplot(r_melted) + \
    ggplot2.geom_boxplot(aes_string(**{"x": "factor(variable, levels = %s)" % labels,
                                       "y": "value"
                                       "fill": "group"})) + \
    ggplot2.scale_fill_manual(values=np.array(["#00BA38", "#F8766D"])) + \
    ggplot2.coord_flip()

如果 labels 列表比较长(或者你不想用任何R代码):

# r_melted is the one defined upstream of your code snippet,
# not the results of calling r.transform()
from rpy2.robjects.vectors import FactorVector
variable_i = r_melted.names.index('variable')
r_melted[variable_i] = FactorVector(r_melted[variable_i],
                                    levels = robj.StrVector(tuple(["a", "b", "c"]))
p = ggplot2.ggplot(r_melted) + \
    ggplot2.geom_boxplot(aes_string(**{"x": "variable",
                                       "y": "value"
                                       "fill": "group"})) + \
    ggplot2.scale_fill_manual(values=np.array(["#00BA38", "#F8766D"])) + \
    ggplot2.coord_flip()

撰写回答