Python中的R group_by()+rleid()等价物

2024-10-05 14:28:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我在Python中得到了以下数据帧:

df = pd.DataFrame.from_dict({'measurement_id': np.repeat([1, 2], [6, 6]),
                         'min': np.concatenate([np.repeat([1, 2, 3], [2, 2, 2]), 
                                                np.repeat([1, 2, 3], [2, 2, 2])]),
                         'obj': list('AB' * 6),
                         'var': [1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 1, 1]})

首先,在由object定义的每个组中,我想将id分配给measurement_idvar列的唯一运行。如果这些列的任何值发生更改,它将启动新的运行,该运行应被分配新的id

df['rleid_output'] = [1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 3]

然后,对于rleid_output定义的每个组,我想检查运行持续了多少分钟(min列),并给出expected_output列:

df['expected_output'] = [2, 2, 2, 2, 1, 1, 2, 3, 2, 3, 1, 3]

如果是R,我会按以下步骤进行:

df <- data.frame(measurement_id = rep(1:2, each = 6),
           min = rep(rep(1:3, each = 2), 2),
           object = rep(LETTERS[1:2], 6),
           var = c(1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 1, 1))
df %>% 
  group_by(object) %>% 
  mutate(rleid = data.table::rleid(measurement_id, var)) %>% 
  group_by(object, rleid) %>% 
  mutate(expected_output = last(min) - first(min) + 1) 

因此,我需要的主要内容是使用Pythonpd.DataFrame.groupby子句的Rdata.table::rleid等价物。有什么办法解决这个问题吗?你知道吗

@Edit:new,更新的数据帧示例:

df = pd.DataFrame.from_dict({'measurement_id': np.repeat([1, 2], [6, 6]),
                         'min': np.concatenate([np.repeat([1, 2, 3], [2, 2, 2]), 
                                                np.repeat([1, 2, 3], [2, 2, 2])]),
                         'obj': list('AB' * 6),
                         'var': [1, 2, 2, 2, 1, 1, 2, 1, 2, 1, 1, 1]})
df['rleid_output'] = [1, 1, 2, 1, 3, 2, 4, 3, 4, 3, 5, 3]
df['expected_output'] = [1, 2, 1, 2, 1, 1, 2, 3, 2, 3, 1, 3]

Tags: 数据iddataframedfoutputobjectvarnp
2条回答

为了模拟Rrleid函数的行为,可以首先创建一个人工列,检查当前值与前一个值相比是否发生了变化。在这种情况下,我们应该对分组的var系列执行此操作:

var_grpd = df.groupby(['measurement_id', 'obj'])['var']
df['tmp'] = (var_grpd.shift(0) != var_grpd.shift(1))

然后,我们可以使用这个人工的tmp列来获得rleid_output2。之后,不再需要tmp列。你知道吗

df['rleid_output2'] = df.groupby('obj')['tmp'].cumsum().astype(int)
df.drop('tmp', axis = 1, inplace = True)

最后,为了检查var值持续了多少分钟,我们可以计算组中最后一分钟和第一分钟之间的差异。你知道吗

df['expected_output2'] = df.groupby(['obj', 'rleid_output2'])['min'] \
                           .transform(lambda x: x.iat[-1] - x.iat[0] + 1)

.iat.iloc类似,但允许我们访问DataFrameSeries中的单个值。你知道吗

更新答案

问题是每个measurement_id, obj, var组中的min列应该保持顺序。我们可以通过分组检查measurement_id, obj, var,然后检查min列中的差异是否大于1。如果是这样,我们在expected_output中将其标记为唯一的持续时间:

df['grouper'] = (df.groupby(['measurement_id', 'obj', 'var'])['min']
                 .apply(lambda x: x.diff().fillna(1).eq(1))
                )

df['expected_output'] = (
    df.groupby(['measurement_id', 'obj', 'var'])['grouper'].transform('sum').astype(int)
)

df = df.drop(columns='grouper')

    measurement_id  min obj  var  expected_output
0                1    1   A    1                1
1                1    1   B    2                2
2                1    2   A    2                1
3                1    2   B    2                2
4                1    3   A    1                1
5                1    3   B    1                1
6                2    1   A    2                2
7                2    1   B    1                3
8                2    2   A    2                2
9                2    2   B    1                3
10               2    3   A    1                1
11               2    3   B    1                3

旧答案,遵循OP的逻辑

我们可以通过使用GroupBy.diff来获得您的rleid_output,这基本上是每次var为每个measurement_id&;obj更改时的唯一标识符

之后使用GroupBy.nunique来测量minutes的量:

rleid_output = df.groupby(['measurement_id', 'obj'])['var'].diff().abs().bfill()
df['expected_output'] = (df.groupby(['measurement_id', 'obj', rleid_output])['min']
                         .transform('nunique'))

    measurement_id  min obj  var  expected_output
0                1    1   A    1                2
1                1    1   B    2                2
2                1    2   A    1                2
3                1    2   B    2                2
4                1    3   A    2                1
5                1    3   B    1                1
6                2    1   A    2                2
7                2    1   B    1                3
8                2    2   A    2                2
9                2    2   B    1                3
10               2    3   A    1                1
11               2    3   B    1                3

相关问题 更多 >