Распределить строку по другим строкам с одинаковым ключом - PullRequest
1 голос
/ 07 января 2020

У меня есть кадр данных, который выглядит следующим образом:

+------+------------+-------+--------------+
| name |    date    | value | replacement |
+------+------------+-------+--------------+
| A    | 20/11/2016 |    10 | NaN          |
| C    | 20/11/2016 |    8  | [A,B]        |
| B    | 20/11/2016 |    12 | NaN          |
| E    | 25/12/2016 |    16 | NaN          |
| F    | 25/12/2016 |    18 | NaN          |
| D    | 25/12/2016 |    11 | [E,F]        |
+------+------------+-------+--------------+

Что я хотел бы сделать:
Для каждой строки, в которой есть список имен в столбце 'замена' , я бы хотел, чтобы его 'value' было равномерно распределено по строкам, содержащим эти замены + для той же даты.
Для предыдущего примера выходные данные будут выглядеть следующим образом:

+------+------------+-------+------------------+
| name |    date    | value | additional value |
+------+------------+-------+------------------+
| A    | 20/11/2016 |    10 |                4 |
| B    | 20/11/2016 |    12 |                4 |
| A    | 25/12/2016 |    16 |              5.5 |
| B    | 25/12/2016 |    18 |              5.5 |
+------+------------+-------+------------------+

Мне удалось найти способ выполнить распределение напрямую, не создавая новый столбец, разделив эти строки и сгруппировав по имени + дате, но 1 / это было слишком медленно + 2 / мне нужно создать этот дополнительный столбец и не могу найти способ сделать это.

Ответы [ 2 ]

1 голос
/ 07 января 2020

Идея состоит в том, чтобы создать новый столбец длиной replacement списков с Series.str.len, а затем DataFrame.explode (pandas 0.25+) в скаляры. Разделите столбцы value на new и merge по оригиналу с именами других столбцов для добавления исходных столбцов:

df1 = df.assign(new=df['replacement'].str.len()).explode('replacement')
df1['new'] = df1['value'].div(df1['new'])

df1 = df1[['name','date','value']].merge(df1[['replacement','date','new']],
                                    left_on=['name','date'],
                                    right_on=['replacement','date'])
df1['replacement'] = df1.pop('new')
print (df1)
  name        date  value  replacement
0    A  20/11/2016     10          4.0
1    B  20/11/2016     12          4.0
2    A  25/12/2016     16          5.5
3    B  25/12/2016     18          5.5

Аналогичное решение с удалением вместо выбора:

df1 = df.assign(new=df['replacement'].str.len()).explode('replacement')
df1['new'] = df1['value'].div(df1['new'])

df1 = df1.drop(['replacement','new'],1).merge(df1.drop(['name','value'],1),
                                        left_on=['name','date'],
                                        right_on=['replacement','date'])
df1['replacement'] = df1.pop('new')
print (df1)
  name        date  value  replacement
0    A  20/11/2016     10          4.0
1    B  20/11/2016     12          4.0
2    A  25/12/2016     16          5.5
3    B  25/12/2016     18          5.5
0 голосов
/ 07 января 2020

Вот еще один способ использования explode (требуется pandas 0.25+) с groupby:

m = df[[isinstance(i,list) for i in df.replacement]] #df which has lists in replacement col

g = m.explode('replacement').groupby('date') #explode and groupby by date
#drop indices of m and assign the divided value
final = df.drop(m.index).set_index('date').assign(
      replacement=(g['value'].mean()/g.size())).reset_index() 

         date name  value  replacement
0  20/11/2016    A   10.0          4.0
1  20/11/2016    B   12.0          4.0
2  25/12/2016    A   16.0          5.5
3  25/12/2016    B   18.0          5.5
...