【问题标题】:how to make a group from different columns based on a condition?如何根据条件从不同的列中创建一个组?
【发布时间】:2021-05-05 21:41:33
【问题描述】:

我有一个如下所示的数据框:

    Air-line        City        Time        ID

0   easyJet         London      20:40       1
1   airberlin       Berlin      10:30       2
2   Emarite         Dubai       21:45       3
3   Qatar Airways   Newyork     10:30       4
4   easyJet         London      20:46       5
5   airberlin       Berlin      10:34       6
.
.
.
.
99   Qatar Airways   London      20:40     13
100   airberlin    Berlin        10:32     20

我想要做的是使用 groupby 并根据列 ID 从列“Air-lines”、“City”和“Time”组成一个组,以更改列 ID 中的值。因此,Air-line、City 和 Time 中具有相同值的行应该具有相同的 ID。为此,我有以下代码:

df['ID'] = df.groupby(['Air-line','City','Time'])['ID'].transform('first') 

但问题是我想更改代码,以便不仅包含“时间”列中的确切值,还应包含 +6 或 -6 分钟之间的差值。

我的期望是这样的:

    Air-line        City        Time        ID

0   easyJet         London      20:40       1
1   airberlin       Berlin      10:30       2
2   Emarite         Dubai       21:45       3
3   Qatar Airways   Newyork     10:30       4
4   easyJet         London      20:46       1
5   airberlin       Berlin      10:34       2
.
.
.
.
99   Qatar Airways   London      20:40       13
100   airberlin    Berlin         10:32       2

你能告诉我如何添加这个条件吗?任何帮助将不胜感激。 非常感谢

【问题讨论】:

  • 考虑以 6 分钟的步长将时间列设为分类。然后分组将按预期工作。
  • @MaximIvanov 你能告诉我应该使用哪个函数吗?我对熊猫不是很熟悉

标签: python pandas conditional-statements pandas-groupby


【解决方案1】:

您可以使用 6 分钟的步骤对 time 列进行分类,如下所示。 我在这里使用pandas.cut 函数。 作为bins,我传递了从pd.date_range 检索到的一系列日期时间对象。 在pd.cut 中,我使用right=False 来包含区间左侧的点并排除区间右侧的点。

我以一个小数据框为例,但你会明白的。

import datetime

import pandas as pd


df = pd.DataFrame({
    'time': ['20:30', '20:33', '20:36', '20:40', '20:42'],
    'ID': [1, 2, 3, 4, 5],
})
df['time'] = pd.to_datetime(df['time'])

start = df['time'].min()
end = df['time'].max() + pd.Timedelta('6min')
bins = pd.date_range(start, end, freq='6T')

cut = pd.cut(df['time'], bins=bins, right=False)
df['time_category'] = cut

df['ID'] = df.groupby('time_category')['ID'].transform('first')

print(df)

输出

                 time  ID                               time_category
0 2021-02-03 20:30:00   1  [2021-02-03 20:30:00, 2021-02-03 20:36:00)
1 2021-02-03 20:33:00   1  [2021-02-03 20:30:00, 2021-02-03 20:36:00)
2 2021-02-03 20:36:00   3  [2021-02-03 20:36:00, 2021-02-03 20:42:00)
3 2021-02-03 20:40:00   3  [2021-02-03 20:36:00, 2021-02-03 20:42:00)
4 2021-02-03 20:42:00   5  [2021-02-03 20:42:00, 2021-02-03 20:48:00)

没有日期的分档

还有另一种方法。 您提到您需要避免在分组中使用日期。 不幸的是,我没有设法使用 pandas 内部组件来扩展解决方案。 但这可以通过其他方式实现。

让我们从 00:00 到 23:54 手动创建bins,并为每个人分配密钥。 然后我们将使用categorize 函数将相应的键分配给时间值。 请注意,这里我创建了new_time 列,它利用了time.strptime 转换。 就是这个专栏,然后我对其进行分类。

import itertools
from functools import partial
import time

import pandas as pd

bins = [
    time.strptime(f'{hour}:{minute}', '%H:%M')
    for hour, minute in itertools.product(range(24), range(0, 60, 6))
]

bins_mapping = {
    index: value
    for index, value in enumerate(sorted(bins))
}


def categorize(t, bins_mapping):
    for index, value in bins_mapping.items():
        if value > t:
            break
    return index


df = pd.DataFrame({
    'time': ['20:30', '20:33', '20:36', '20:40', '20:42'],
    'ID': [1, 2, 3, 4, 5],
})

df['new_time'] = df['time'].apply(lambda x: time.strptime(x, '%H:%M'))
df['time_category'] = df['new_time'].apply(
    partial(categorize, bins_mapping=bins_mapping)
)
df['ID'] = df.groupby('time_category')['ID'].transform('first')

print(df)

输出

    time  ID                           new_time  time_category
0  20:30   1  (1900, 1, 1, 20, 30, 0, 0, 1, -1)            206
1  20:33   1  (1900, 1, 1, 20, 33, 0, 0, 1, -1)            206
2  20:36   3  (1900, 1, 1, 20, 36, 0, 0, 1, -1)            207
3  20:40   3  (1900, 1, 1, 20, 40, 0, 0, 1, -1)            207
4  20:42   5  (1900, 1, 1, 20, 42, 0, 0, 1, -1)            208

【讨论】:

  • 感谢您的回答。但我仍然没有开始和结束。我可以使用没有开始和结束的垃圾箱吗?@MaximIvanov
  • @lerner12 您可以根据time 列中的数据定义开始和结束。在这种情况下,start 将对应于time 的最小值,而end - 最大值。
  • @lerner12 我提供了一个更自动化的示例。请检查这个。
  • @lerner12 你能确认答案是否对你有帮助吗?
  • @Maxim Ivanov 我正在尝试将其调整为我的数据。问题是我的数据中的时间列应该只是没有日期的时间,这样我就不能像你在这里那样使用开始和结束。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-21
  • 1970-01-01
  • 2011-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-24
相关资源
最近更新 更多