Эффективный способ задания условных значений - PullRequest
0 голосов
/ 23 мая 2018

У меня есть pandas DataFrame операций в моем приложении:

+----------+-------------+
| UserName |  StartEdit  |
+----------+-------------+
| John     | 12-Jul-2015 |
| David    | 16-Aug-2015 |
| Katie    | 20-Aug-2015 |
| Cristin  | 2-Sep-2015  |
| Katie    | 12-Sep-2015 |
| John     | 23-Nov-2015 |
| David    | 2-Jan-2016  |
| David    | 3-Jan-2016  |
| John     | 10-Feb-2016 |
| Steven   | 13-Mar-2016 |
| Steven   | 14-Mar-2016 |
+----------+-------------+

Я хотел бы создать еще один столбец с UserTeam.Я знаю, что Кэти, Кристин и Стивен всегда были в одной команде:

owners_teams = {"Katie":"A", "Cristin":"B", "Steven":"C"}

Поэтому, когда я делаю df["UserTeam"] = df["UserName"].map(owners_teams), я получаю:

+----------+-------------+----------+
| UserName |  StartEdit  | UserTeam |
+----------+-------------+----------+
| John     | 12-Jul-2015 | NaN      |
| David    | 16-Aug-2015 | NaN      |
| Katie    | 20-Aug-2015 | A        |
| Cristin  | 2-Sep-2015  | B        |
| Katie    | 12-Sep-2015 | A        |
| John     | 23-Nov-2015 | NaN      |
| David    | 2-Jan-2016  | NaN      |
| David    | 3-Jan-2016  | NaN      |
| John     | 10-Feb-2016 | NaN      |
| Steven   | 13-Mar-2016 | C        |
| Steven   | 14-Mar-2016 | C        |
+----------+-------------+----------+

Теперь я также знаю, что:

Джон перешел с A на C на 01-Jan-2016

Дэвид перешел с B на C на 12-Dec-2015

changes = [("John", "01-Jan-2016", "A", "C"), ("David", "12-Dec-2015", "B", "C")]

Я знаю, как сделать это с apply и циклически проходить по строкам и жестко кодировать все правила, но я не думаю, что это эффективно.Как мне сделать это векторизованным способом для большого количества пользователей?

Ожидаемый результат:

+----------+-------------+----------+
| UserName |  StartEdit  | UserTeam |
+----------+-------------+----------+
| John     | 12-Jul-2015 | A        |
| David    | 16-Aug-2015 | B        |
| Katie    | 20-Aug-2015 | A        |
| Cristin  | 2-Sep-2015  | B        |
| Katie    | 12-Sep-2015 | A        |
| John     | 23-Nov-2015 | A        |
| David    | 2-Jan-2016  | C        |
| David    | 3-Jan-2016  | C        |
| John     | 10-Feb-2016 | C        |
| Steven   | 13-Mar-2016 | C        |
| Steven   | 14-Mar-2016 | C        |
+----------+-------------+----------+

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

pd.merge_asof

Это идеальный вариант использования для pd.merge_asof, но требует, чтобы вы отслеживали изменения.Настройте другой фрейм данных teams, который выполняет это отслеживание.

Примечание

  • Я использовал начальную дату, которая была минимальной датой, найденной в df.
  • Я настроил Джона и Дэвидас указанными вами начальными командами, а также с начальными датами.
  • Я добавил еще одну запись, чтобы показать, когда Джон и Дэвид сменили команды.

teams = pd.DataFrame([
    ['Katie', 'A', pd.Timestamp('2015-07-12')],
    ['Cristin', 'B', pd.Timestamp('2015-07-12')],
    ['Steven', 'C', pd.Timestamp('2015-07-12')],
    ['John', 'A', pd.Timestamp('2015-07-12')],
    ['David', 'B', pd.Timestamp('2015-07-12')],
    ['David', 'C', pd.Timestamp('2015-12-12')],
    ['John', 'C', pd.Timestamp('2016-01-01')],
], columns=['UserName', 'Team', 'StartEdit'])

teams

  UserName Team  StartEdit
0    Katie    A 2015-07-12
1  Cristin    B 2015-07-12
2   Steven    C 2015-07-12
3     John    A 2015-07-12
4    David    B 2015-07-12
5    David    C 2015-12-12
6     John    C 2016-01-01

Согласно документам,убедитесь, что оба кадра данных отсортированы по соответствующим столбцам даты.

pd.merge_asof(df, teams, on='StartEdit', by='UserName')

   UserName  StartEdit Team
0      John 2015-07-12    A
1     David 2015-08-16    B
2     Katie 2015-08-20    A
3   Cristin 2015-09-02    B
4     Katie 2015-09-12    A
5      John 2015-11-23    A
6     David 2016-01-02    C
7     David 2016-01-03    C
8      John 2016-02-10    C
9    Steven 2016-03-13    C
10   Steven 2016-03-14    C
0 голосов
/ 23 мая 2018

Одним из способов является использование pd.DataFrame.loc в цикле for.С точки зрения эффективности, вы должны проверить и посмотреть, является ли это эффективным для вашего варианта использования.

changes = [("John", "01-Jan-2016", "A", "C"), ("David", "12-Dec-2015", "B", "C")]

for name, date, before, after in changes:
    name_mask = df['UserName'] == name
    df.loc[name_mask & (df['StartEdit'] < date), 'UserTeam'] = before
    df.loc[name_mask & (df['StartEdit'] >= date), 'UserTeam'] = after

Вы также можете выполнить эквивалентное сопоставление через numpy.where.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...