如何使用pandas索引唯一值组合

3
我正在处理学校的课程表数据,需要区分同一门课程的不同时间段。
如果另一个班级有相同的课程,则实际上是该课程的另一个时间段,需要进行区分。这意味着需要添加一个带有会话索引的额外列。
import pandas as pd

cols = ['course', 'class_name', 'professor']

data = [ ['Math',    'X', 'Bob'],
         ['Math',    'X', 'Bob'], 
         ['Math',    'Y', 'Bob'],
         ['English', 'Y', 'Tim'],
         ['English', 'X', 'Jim'],
         ['English', 'X', 'Jim'],
       ]

df = pd.DataFrame(columns=cols, data=data)

# Add session
df['session'] = '?'
print(df)

结果应该类似于这样。
    course  class_name  professor   session
0   Math    X   Bob     0
1   Math    X   Bob     0
2   Math    Y   Bob     1
3   Eng.    Y   Tim     1
4   Eng.    X   Jim     0
5   Eng.    X   Jim     0

我想找一个更简单的 pandas 方式来解决这个问题,目前的方法过于复杂。

groups = df.groupby(['course', 'class_name'])

d_sessions = {}
counter = 0
pclass = ""
pcourse = ""

for m_idx in list(groups.groups):
    course = m_idx[0]
    class_ = m_idx[1]

    if class_ != pclass:
        counter += 1

    if pcourse != course:
        counter = 0

    pclass = class_
    pcourse = course    
    d_sessions[m_idx] = counter

df.set_index(['course', 'class_name'], inplace=True)

for k, v in d_sessions.items():
    df.set_value(col='index', value=v, index=k)

df.reset_index(inplace=True)
df
2个回答

3

让我们来试试:

df['session'] = df.groupby('course')['class_name'].transform(lambda x: (~x.duplicated()).cumsum())

输出:

    course class_name professor  session
0     Math          X       Bob        1
1     Math          X       Bob        1
2     Math          Y       Bob        2
3  English          Y       Tim        1
4  English          X       Jim        2
5  English          X       Jim        2

1

有趣的问题。

尝试制作一个地图,显示所有唯一组合及其会话编号。

导入数据到df中(请注意,我添加了一些行来验证我的解决方案):

import pandas as pd

cols = ['course', 'class_name', 'professor']

data = [ ['Math',    'X', 'Bob'],
         ['Math',    'X', 'Bob'],
         ['Math',    'X', 'Bob'], 
         ['Math',    'Y', 'Bob'],
         ['English', 'Y', 'Tim'],
         ['English', 'X', 'Jim'],
         ['English', 'X', 'Jim'],
         ['English', 'Z', 'Mark'],
         ['Chinese', 'X', 'Mark'],
         ['Chinese', 'X', 'Mark'],
         ['Chinese', 'F', 'Mark'],
       ]

df = pd.DataFrame(columns=cols, data=data)

然后为每个独特的课程-班级组合创建一个地图,并为它们分配会话编号。我正在这样做的方式是通过课程切片框架,然后找到该课程的唯一班级值。然后为每个组合创建一个唯一名称,并为每个会话(每门课程)分配一个唯一的会话编号。然后将会话列与字典叠加:

def sol():
    map = {}

    for item in df.course.unique():
        slice = df[df['course'] == item]
        mapslice = dict(zip(item + slice.class_name.unique(), 
        list(range(len(slice.class_name.unique())))))
        map.update(mapslice)

    df['session'] = (df.course + df.class_name).map(map)

    return df

这将样本数据返回为:

course  class_name  professor   session
0   Math    X   Bob 0
1   Math    X   Bob 0
2   Math    X   Bob 0
3   Math    Y   Bob 1
4   English Y   Tim 0
5   English X   Jim 1
6   English X   Jim 1
7   English Z   Mark    2
8   Chinese X   Mark    0
9   Chinese X   Mark    0
10  Chinese F   Mark    1

然后进行快速性能检查:
%timeit sol()

3.66 ms ± 44 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

与您的解决方案(这里称为ori)相比:
%timeit ori()
4.4 ms ± 10.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

感谢您告诉我这个答案是否有帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接