【问题标题】:Reproduce R's summarise/reshape result in Python在 Python 中重现 R 的 summarise/reshape 结果
【发布时间】:2017-02-28 19:05:35
【问题描述】:

我想在使用 Python 的 melt 函数时重现行为或 R 的 aggregate 函数。

R中数据如下:

library("dplyr")

data <- summarise(group_by(table, project, resourcetype), 
                  count = n_distinct(resource_id))

  project resourcetype count
   <fctr>       <fctr> <int>
1 1000001            O     7
2 1000002            O     6
3 1000003            O    18
4 1000004            C     1
5 1000004            I     1
6 1000004            O    19
7 1000005            I     2
8 1000005            O    11
9 1000006            O     4

reshape(as.data.frame(data), 
        timevar = "resourcetype", 
        idvar = "project", 
        direction = "wide", 
        sep = "_")

  project count_O count_C count_I
1 1000001       7      NA      NA
2 1000002       6      NA      NA
3 1000003      18      NA      NA
4 1000004      19       1       1
7 1000005      11      NA       2
9 1000006       4      NA      NA

现在,在 Python 中我得到:

import pandas as pd

data = table.groupby(['project', 'resourcetype'], as_index=False)\
       .agg({'resource_id': {'count': 'nunique'}})

   project resourcetype resource_id
                              count
0  1000001            O           7
1  1000002            O           6
2  1000003            O          18
3  1000004            C           1
4  1000005            I           1
5  1000006            O          19
6  1000007            I           2
7  1000008            O          11
8  1000009            O           4

我有多重索引,我希望用as_index=False 消除它。我在最后一列中有resource_idcount,我只想在R 中使用count

我试图在 Python 中使用 melt 函数,但无济于事。

编辑:原始数据是一个2000行19列的表格。

Edit2:关于多索引问题。

table.groupby(['project', 'resourcetype'])\
.agg({'resource_id': {'count': 'nunique'}}).reset_index()
   project resourcetype resource_id
                              count
0  1000001            O           7

table.groupby(['project', 'resourcetype'])\
.agg({'resource_id': {'count': 'nunique'}})
                     resource_id
                           count
project resourcetype                   
1000001 O                      7

我想得到的是:

   project resourcetype count
0  1000001            O     7

【问题讨论】:

  • 您使用的不是基本 R 而是另一个库的 dplyr 行。请包括所有 R 库行。

标签: python r pandas dplyr


【解决方案1】:

考虑 pandas 的 pivot 更新列名:

from io import StringIO
import pandas as pd

# REPRODUCIBLE EXAMPLE
text ="""
project resourcetype count
1000001            O     7
1000002            O     6
1000003            O    18
1000004            C     1
1000004            I     1
1000004            O    19
1000005            I     2
1000005            O    11
1000006            O     4
"""    
df = pd.read_table(StringIO(text), sep="\s+")

# PIVOTED DATA
pvtdf = df.pivot(index='project', columns='resourcetype', values='count')

# RENAME COLUMNS WITH RESET_INDEX
pvtdf.columns = ['count_'+str(i) for i in pvtdf.columns.values]
pvtdf = pvtdf.reset_index()

print(pvtdf)
#    project  count_C  count_I  count_O
# 0  1000001      NaN      NaN      7.0
# 1  1000002      NaN      NaN      6.0
# 2  1000003      NaN      NaN     18.0
# 3  1000004      1.0      1.0     19.0
# 4  1000005      NaN      2.0     11.0
# 5  1000006      NaN      NaN      4.0

【讨论】:

  • 谢谢,pivot 可以满足我的要求。只剩下一个问题——当我在 Python 中运行 data = table.groupby(...).agg(...) 时,我得到了多索引 df,所以我没有和你一样的起点。 data.columns = MultiIndex(levels=[['resource_id', 'resourcetype', 'project'], ['count', '']], labels=[[2, 1, 0], [1, 1, 0]])。知道如何不获取多索引或以后如何将其展平吗?我试过data.reset_index(),没有任何变化。
  • 你为什么要做groupby(...).agg(...)?这不是试图重现 R 输出吗?我建议将其完全替换为枢轴。还是这是您的意见?
  • 原始数据是一个 2000 x 19 的表格。我使用groupby(...).agg(...) 首先将其处理为只有 3 列:projectresourcetypecount。从那一刻起,我喜欢您的pivot() 解决方案。当然,如果您看到仅使用 pivot() 从原始表到最终解决方案的选项,我完全赞成:) 现在我只是使用 data.columns = ['project', 'resourcetype', 'count'] 来展平多索引,但我很想拥有在聚合表格后直接采用这种方式,无需手写名称。我在原始问题中添加了有关原始数据的信息。
  • 当您尝试reset_index() 时,您是否将其分配回数据:data = data.reset_index()?或者你可以把它链接到groupby:data = table.groupby(...).agg(...).reset_index()
  • 我编辑了(#2)我的问题并粘贴了 dfs 在有和没有reset_index() 的情况下的样子。我在测试时将结果打印到屏幕上。
【解决方案2】:

显而易见的解决方案:)

import pandas
import rpy2
from rpy2 import robjects
from rpy2.robjects import pandas2ri

rdf = robjects.r('''
data <- summarise(group_by(table, project, resourcetype), 
                  count = n_distinct(resource_id))
data <- summarise(group_by(table, project, resourcetype), 
                  count = n_distinct(resource_id))
                  reshape(as.data.frame(data), 
        timevar = "resourcetype", 
        idvar = "project", 
        direction = "wide", 
        sep = "_")
        data[is.na(data)] <- NaN
        data
''')

pd_df = pandas2ri.ri2py_dataframe(rdf)

【讨论】:

  • 好吧,至少可以说,这不是我想要的解决方案。
  • 为什么? R 语法对于数据处理 (IMO) 来说更加自然。如果您也可以在 python 中轻松集成这些功能,则没有理由切换。
  • 我同意 R 语法对用户更友好。不幸的是,我应该将代码从 R 迁移到 Python。我不能让 R 在后台运行。
【解决方案3】:

除了reshape,我们还可以使用tidyrpivot_wider

r$> library(tidyr)
r$> library(dplyr)
r$> data = tribble( 
      ~project, ~resourcetype, ~count, 
      1000001,  "O",            7, 
      1000002,  "O",            6, 
      1000003,  "O",           18, 
      1000004,  "C",            1, 
      1000004,  "I",            1, 
      1000004,  "O",           19, 
      1000005,  "I",            2, 
      1000005,  "O",           11, 
      1000006,  "O",            4 
    ) 
r$> pivot_wider(
        data, 
        names_from=resourcetype, 
        values_from=count,
        names_glue="count_{.resourcetype}"
    )                                                                               
# A tibble: 6 x 4
  project count_O count_C count_I
    <dbl>   <dbl>   <dbl>   <dbl>
1 1000001       7      NA      NA
2 1000002       6      NA      NA
3 1000003      18      NA      NA
4 1000004      19       1       1
5 1000005      11      NA       2
6 1000006       4      NA      NA

在 python 中,您可以使用 datar 复制它:

>>> from datar.all import f, tribble, pivot_wider
>>> 
>>> df = tribble(
...     f.project, f.resourcetype, f.count,
...     1000001,   "O",            7,
...     1000002,   "O",            6,
...     1000003,   "O",            18,
...     1000004,   "C",            1,
...     1000004,   "I",            1,
...     1000004,   "O",            19,
...     1000005,   "I",            2,
...     1000005,   "O",            11,
...     1000006,   "O",            4,
... )
>>> df >> pivot_wider(
...     names_from=f.resourcetype,
...     names_glue="count_{resourcetype}",
...     values_from=f.count,
... )
   project   count_C   count_I   count_O
   <int64> <float64> <float64> <float64>
0  1000001       NaN       NaN       7.0
1  1000002       NaN       NaN       6.0
2  1000003       NaN       NaN      18.0
3  1000004       1.0       1.0      19.0
4  1000005       NaN       2.0      11.0
5  1000006       NaN       NaN       4.0

免责声明:我是datar 包的作者。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-25
    • 1970-01-01
    • 2017-11-22
    • 1970-01-01
    • 2012-09-04
    • 1970-01-01
    相关资源
    最近更新 更多