从 Pandas groupby 对象中收集系列

Collecting series from Pandas groupby object

我正在处理如下国际象棋结果的数据框

    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's 作为 '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

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


我的想法:我想按时间排序,然后将专栏作为 pandas 系列。问题是如何在按对手和日期分组的同时(即在之后)执行此操作。

如果你有这个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

你走在正确的轨道上。只需重命名带有所需标签的列:

df1=pd.crosstab([df['Opponent'], df['Date']],
            df['Result']).reset_index().rename(columns={1.0:'W',0.5:'D',0.0:'L'})

创建新列,在其中根据列值连接相关列的一部分

df1['result_seq'] = df1.iloc[:,2:].mul(df1.iloc[:,2:].columns.values).sum(axis=1)



Result Opponent        Date  L  D  W result_seq
0         Anish  2020.03.03  1  1  0         LD
1         Anish  2020.03.04  0  2  1        DDW
2        Hikaru  2020.03.02  0  1  1         DW
3        Hikaru  2020.03.03  1  1  2       LDWW