首页 > 解决方案 > 从 Pandas groupby 对象中收集系列

问题描述

我正在使用国际象棋结果的数据框,如下所示

    Opponent    Date    Time    Result
0   Hikaru  2020.03.02  01:22:54    1
1   Hikaru  2020.03.02  01:22:58    0.5
2   Hikaru  2020.03.03  01:18:17    1
3   Hikaru  2020.03.03  01:19:54    0
4   Hikaru  2020.03.03  01:19:45    1
5   Hikaru  2020.03.03  02:15:23    0.5
6   Anish   2020.03.03  02:21:25    0.5
7   Anish   2020.03.03  02:21:29    0
8   Anish   2020.03.04  15:45:12    1
9   Anish   2020.03.04  15:48:11    0.5
10  Anish   2020.03.04  16:05:01    0.5

现在我想(1)按对手分组,(2)按日期分组(在对手内),(3)将每个结果的计数制成表格,(4)给出获得的结果序列。前 3 个可以通过pd.crosstab例如 - 一个完整的例子 -

import pandas as pd

d = {'Opponent': ['Hikaru']*6 + ['Anish']*5,
     'Date': ['2020.03.02']*2 + ['2020.03.03']*6 + ['2020.03.04']*3,
    'Time': ['01:22:54', '01:22:58', '01:18:17', '01:19:54', '01:19:45', '02:15:23', '02:21:25', '02:21:29', '15:45:12', '15:48:11', '16:05:01'],
    'Result': ['1', '0.5', '1', '0', '1', '0.5', '0.5', '0', '1', '0.5', '0.5']}

df = pd.DataFrame(data = d)

pd.crosstab([df['Opponent'], df['Date']],
            df['Result'])

我想要的是与最后一个相同的输出,pd.crosstab但是添加了一个列,显示了两位玩家在当天的比赛中的结果序列(按时间排序),按时间排序。理想情况下,我希望'1'作为'W',0.5s 作为'D',0s 作为'L',并在列中使用一个长字符串。

期望的输出:


                    Result  0   0.5 1   result_seq
Opponent    Date                
Anish   2020.03.03  1   1   0   DL
        2020.03.04  0   2   1   WDD
Hikaru  2020.03.02  0   1   1   WD
        2020.03.03  1   1   2   WWLD

请注意,在原始数据框中,不保证游戏/结果按时间顺序列出;在原始数据框中,每个变量的数据类型都是str,我想在最终输出中保持这种状态(例如Results,应该保留为 '1'、'0'、'0.5' 字符串,而不是 '1.0'、' 0.5, '0.0', Dates 最终应该是字符串;只有实际结果计数可以并且可能是整数)。


我的想法:我想只是按时间排序,然后将专栏作为熊猫系列。问题是如何与对手和日期的分组一起(即之后)做到这一点。

标签: pythonpandasdataframepandas-groupbycrosstab

解决方案


如果你有这个df

   Opponent        Date      Time  Result
0    Hikaru  2020.03.02  01:22:54     1.0
1    Hikaru  2020.03.02  01:22:58     0.5
2    Hikaru  2020.03.03  01:18:17     0.0
3    Hikaru  2020.03.03  01:19:45     1.0
4    Hikaru  2020.03.03  01:19:54     1.0
5    Hikaru  2020.03.03  02:15:23     0.5
6     Anish  2020.03.03  02:21:25     0.5
7     Anish  2020.03.03  02:21:29     0.0
8     Anish  2020.03.04  15:45:12     1.0
9     Anish  2020.03.04  15:48:11     0.5
10    Anish  2020.03.04  16:05:01     0.5

然后你可以使用.pivot_table()来获得你的结果:

df_out = df.pivot_table(
    index=["Opponent", "Date"],
    columns="Result",
    aggfunc="size",
    fill_value=0,
).rename(columns={0.0: "0", 1.0: "1"})

df_out["result_seq"] = df.groupby(["Opponent", "Date"])["Result"].apply(
    lambda x: "".join({0: "L", 1: "W", 0.5: "D"}[v] for v in x)
)
print(df_out)

印刷:

Result               0  0.5  1 result_seq
Opponent Date                            
Anish    2020.03.03  1    1  0         DL
         2020.03.04  0    2  1        WDD
Hikaru   2020.03.02  0    1  1         WD
         2020.03.03  1    1  2       LWWD

编辑:按时间排序值:

df["tmp"] = pd.to_datetime(df.Date + " " + df.Time)
df = df.sort_values(by="tmp").drop(columns="tmp")

df_out = df.pivot_table(
    index=["Opponent", "Date"],
    columns="Result",
    aggfunc="size",
    fill_value=0,
).rename(columns={0.0: "0", 1.0: "1"})

df_out["result_seq"] = df.groupby(["Opponent", "Date"])["Result"].apply(
    lambda x: "".join({0: "L", 1: "W", 0.5: "D"}[v] for v in x)
)
print(df_out)

印刷:

Result               0  0.5  1 result_seq
Opponent Date                            
Anish    2020.03.03  1    1  0         DL
         2020.03.04  0    2  1        WDD
Hikaru   2020.03.02  0    1  1         WD
         2020.03.03  1    1  2       WWLD

推荐阅读