У меня есть 2 кадра данных из следующих
df
:
Name
1 A
2 B
3 C
4 C
5 D
6 D
7 D
8 D
и df_value
:
Name Value
1 A 50
2 B 100
3 C 200
4 D 800
Я хочу объединить оба фрейма данных (в df
), но новый Value
стоит df_value Value
, деленного на количество вхождений Name
в df
Выход :
Name Value
1 A 50
2 B 100
3 C 100
4 C 100
5 D 200
6 D 200
7 D 200
8 D 200
A появляется один раз, имеет значение 50 в df_value
, поэтому его значение равно 50. Та же логика для B.
C появляется 2 раза, имеет значение 200 в df_value
, поэтому его значение 200 / 2 = 100
D появляется 4 раза, имеет значение 800 в df_value
, поэтому его значение 800 / 4 = 200.
Я почти уверен, что есть действительно простой способ сделать это, но я не могу его найти. Заранее спасибо.
Используйте Series.map по столбцу Name
и Series from df_value
и разделите сопоставленные значения Series.value_counts:
df['Value'] = (df['Name'].map(df_value.set_index('Name')['Value'])
.div(df['Name'].map(df['Name'].value_counts())))
print (df)
Name Value
1 A 50.0
2 B 100.0
3 C 100.0
4 C 100.0
5 D 200.0
6 D 200.0
7 D 200.0
8 D 200.0
Еще одно решение, спасибо @sammywemmy, — это сопоставление уже разделенных значений:
df1.assign(Value=df1.Name.map(df2.set_index("Name").Value.div(df1.Name.value_counts())))
Возможно решение с merge
, также добавлена альтернатива для подсчетов от GroupBy.transform:
df['Value'] = (df.merge(df_value, on='Name', how='left')['Value']
.div(df.groupby('Name')['Name'].transform('size')))
@sammywemmy - я запутался, для слияния с левым соединением сбрасывается индекс? Потому что я использую df.merge(df_value, on='Name', how='left')
и индексирую не Int64Index([1, 2, 3, 4, 5, 6, 7, 8], dtype='int64')
, а Int64Index([0, 1, 2, 3, 4, 5, 6, 7], dtype='int64')
. Как вы думаете, это ошибка?
он отлично работает, когда я пробовал. Это дает мне Int64Index([1, 2, 3, 4, 5, 6, 7, 8], dtype='int64')
Я использовал 1-е решение, которое отлично работает, я думаю, что и другие. Большое спасибо за вашу помощь. Кстати, извините за то, что начал свой индекс с 1, это был неразумный ход с моей стороны -_-
Если важно сохранить существующие кадры данных как есть и нет ограничений на использование двух строк кода:
df1 = df.merge(df_value, on='Name', how='left')
df1['Value'] = df1.groupby('Name')[['Value']].transform(lambda x: x/len(x))
В противном случае одно линейное решение, которое немного изменяет существующий 'df'.
df['Value'] = df.merge(df_value, on='Name', how='left').groupby('Name')[['Value']].transform(lambda x: x/len(x))
Оба дают одинаковый результат с разными именами переменных:
Name Value
0 A 50.0
1 B 100.0
2 C 100.0
3 C 100.0
4 D 200.0
5 D 200.0
6 D 200.0
7 D 200.0
Альтернатива вашему решению:
df1.assign(Value=df1.Name.map(df2.set_index("Name").Value.div(df1.Name.value_counts())))