#python #pandas #merge
#python #pandas #слияние
Вопрос:
У меня есть два фрейма данных left
и right
, которые я хочу объединить на основе группировки в df1
.
df1:
ID cumul_growth_perc
Nioz-TC-09-A1R 0
Nioz-TC-09-A1R 2.99881756777804
Nioz-TC-09-A1R 90.1974001442841
Nioz-TC-09-A1R 92.7010664317585
Nioz-TC-09-A1R 95.4937993952028
Nioz-TC-09-A1R 97.7300790074048
Nioz-TC-09-A1R 100
Nioz-TC-09-A2R 0
Nioz-TC-09-A2R 2.1989297984251
Nioz-TC-09-A2R 4.25561486642024
Nioz-TC-09-A2R 82.2910739802899
Nioz-TC-09-A2R 93.276493352502
Nioz-TC-09-A2R 95.5072381936874
Nioz-TC-09-A2R 97.5983443147713
Nioz-TC-09-A2R 100
df2:
day cumul_growth_perc
32 0.233297611918821
33 0.466595223837642
34 0.699892835756464
35 0.933190447675285
36 1.16648805959411
37 1.39978567151293
46 3.54027808151455
47 3.78173847397982
48 4.02319886644508
335 92.4313101347799
336 92.6888317371006
337 92.9463533394213
338 93.203874941742
339 93.4613965440627
340 93.7189181463834
361 99.0468989121531
362 99.2851741841149
363 99.5234494560766
364 99.7617247280384
365 100
cumul_growth_perc
находится в диапазоне от 0-100, но был сокращен здесь для демонстрации. Я хочу объединить оба фрейма данных в этом столбце, и значения не совпадают точно в df1
и df2
.
Кроме того, df1
должны быть сгруппированы по ID
столбцу перед выполнением сопоставления. Насколько я понимаю, у pandas merge_asof
специально есть by=
ключевое слово для этого. Но поскольку у меня нет ID
столбца в df2
, операция завершается с ошибкой. df2
одинаково для всех групп df1
.
Вот что я использовал: pd.merge_asof(df1, df2, on='cumul_growth_perc', left_by='ID', direction='nearest')
Как и ожидалось, это говорит мне right_by is missing
. Как я все еще могу выполнить «групповое слияние»? Я мог бы просто расширить, df2
добавив одинаковые значения для каждого уникального значения в df1.ID
, но это кажется халтурным.
Редактировать:
Ожидаемый результат:
ID cumul_growth_perc day
0 Nioz-TC-09-A1R 0.000000 32
1 Nioz-TC-09-A1R 2.998818 46
2 Nioz-TC-09-A1R 90.197400 335
3 Nioz-TC-09-A1R 92.701066 336
4 Nioz-TC-09-A1R 95.493799 340
5 Nioz-TC-09-A1R 97.730079 361
6 Nioz-TC-09-A1R 100.000000 365
7 Nioz-TC-09-A2R 0.000000 32
8 Nioz-TC-09-A2R 2.198930 37
9 Nioz-TC-09-A2R 4.255615 48
10 Nioz-TC-09-A2R 82.291074 335
11 Nioz-TC-09-A2R 93.276493 338
12 Nioz-TC-09-A2R 95.507238 340
13 Nioz-TC-09-A2R 97.598344 361
14 Nioz-TC-09-A2R 100.000000 365
Это означает, что я хочу сгруппировать по df1.ID
перед выполнением слияния. Я заставил это работать, «повторив» df2
с дополнительным ID
столбцом для каждого идентификатора df1
:
for i, name in enumerate(df1.Shell_ID.unique()):
if i==0:
df2_long = df2.copy()
df2_long['ID'] = name
else:
temp = df2.copy()
temp['ID'] = name
df2_long = df2_long.append(temp)
Затем оба фрейма данных были отсортированы по cumul_growth_perc
, и я объединил их с pd.merge_asof(df1, df2_long, on='cumul_growth_perc', by='ID', direction='nearest')
Но кажется, что есть гораздо более простое решение.
Комментарии:
1. Что вы делаете с группой в df1? Не могли бы вы опубликовать ожидаемый результат?
2. Отредактировал вопрос соответствующим образом
3. @cripcate Я думаю, что значение в строке с
index=3
должно быть336
4. @ShubhamSharma извините, я сделал это на глаз, я отредактирую через минуту.
5. @anky Итак, я обнаружил, что эта группировка на самом деле не нужна, так как
merge_asof
происходит то же самое, когда я опускаюby
аргумент. Единственное, что отличается от моего собственного решения, — это первые три строки.
Ответ №1:
С помощью DataFrame.sort_values
сортировки фреймов данных df1
и df2
далее cumul_growth_perc
затем выполните merge_asof
для отсортированных фреймов данных:
d1 = df1.sort_values('cumul_growth_perc')
d2 = df2.sort_values('cumul_growth_perc')
df = pd.merge_asof(d1, d2, on='cumul_growth_perc', direction='nearest').sort_values('ID')
Результат:
ID cumul_growth_perc day
0 Nioz-TC-09-A1R 0.000000 32
1 Nioz-TC-09-A1R 2.998818 46
2 Nioz-TC-09-A1R 90.197400 335
3 Nioz-TC-09-A1R 92.701066 336
4 Nioz-TC-09-A1R 95.493799 340
5 Nioz-TC-09-A1R 97.730079 361
6 Nioz-TC-09-A1R 100.000000 365
7 Nioz-TC-09-A2R 0.000000 32
8 Nioz-TC-09-A2R 2.198930 37
9 Nioz-TC-09-A2R 4.255615 48
10 Nioz-TC-09-A2R 82.291074 335
11 Nioz-TC-09-A2R 93.276493 338
12 Nioz-TC-09-A2R 95.507238 340
13 Nioz-TC-09-A2R 97.598344 361
14 Nioz-TC-09-A2R 100.000000 365
Ответ №2:
используя tolerance
и direction
параметр, вы можете определить, насколько близкими должны быть значения между собой. как вы видите, value 2.998818
есть ID
NAN
, потому что, например, нет близкого значения из второго df в интервале 3.0
df = pd.DataFrame({
"cumul_growth_perc": [2.99881756777804,90.1974001442841,92.7010664317585],
'day':['one','two','three']
})
print(df)
cumul_growth_perc day
0 2.998818 one
1 90.197400 two
2 92.701066 three
df2= pd.DataFrame({
"cumul_growth_perc": [92.9463533394213, 93.203874941742, 84.00],
'ID':['first','second','3rd']
}).sort_values(by='cumul_growth_perc')
print(df2)
cumul_growth_perc ID
2 84.000000 3rd
0 92.946353 first
1 93.203875 second
res = pd.merge_asof(df,df2,on='cumul_growth_perc',tolerance=3.0,direction='nearest')
print(res)
cumul_growth_perc day ID
0 2.998818 one NaN
1 90.197400 two first
2 92.701066 three first