для цикла, использующего iterrows в пандах

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

data1 выглядит так:

id address 1 11123451 2 78947591 

data2 выглядит следующим образом:

 lowerbound_address upperbound_address place 78392888 89000000 X 10000000 20000000 Y 

Я хочу создать еще один столбец в data1, называемый «местом», который содержит место, откуда находится идентификатор. Например, в приведенном выше случае для id 1 я хочу, чтобы столбец места содержал Y и для id 2, я хочу, чтобы столбец места содержал X. Будет много идентификаторов, поступающих из одного и того же места. И некоторые идентификаторы не имеют соответствия.

Я пытаюсь сделать это, используя следующий фрагмент кода.

 places = [] for index, row in data1.iterrows(): for idx, r in data2.iterrows(): if r['lowerbound_address'] <= row['address'] <= r['upperbound_address']: places.append(r['place']) 

Адреса здесь являются значениями float.

Это навсегда запустит этот кусок кода. Это заставляет меня задаться вопросом, правильный ли мой код или есть ли более быстрый способ его выполнения.

Любая помощь будет высоко ценится. Спасибо!

One Solution collect form web for “для цикла, использующего iterrows в пандах”

Вы можете использовать первое cross соединение с merge а затем фильтровать значения с помощью boolean indexing . Последний удалить ненужные столбцы:

 data1['tmp'] = 1 data2['tmp'] = 1 df = pd.merge(data1, data2, on='tmp', how='outer') df = df[(df.lowerbound_address <= df.address) & (df.upperbound_address >= df.address)] df = df.drop(['lowerbound_address','upperbound_address', 'tmp'], axis=1) print (df) id address place 1 1 11123451 Y 2 2 78947591 X 

Другое решение с itertuples , последнее создание DataFrame.from_records :

 places = [] for row1 in data1.itertuples(): for row2 in data2.itertuples(): #print (row1.address) if (row2.lowerbound_address <= row1.address <= row2.upperbound_address): places.append((row1.id, row1.address, row2.place)) print (places) [(1, 11123451, 'Y'), (2, 78947591, 'X')] df = pd.DataFrame.from_records(places) df.columns=['id','address','place'] print (df) id address place 0 1 11123451 Y 1 2 78947591 X 

Другое решение:

 def f(x): for row2 in data2.itertuples(): if (row2.lowerbound_address <= x <= row2.upperbound_address): return pd.Series([x, row2.place], index=['address','place']) df = data1.set_index('id')['address'].apply(f).reset_index() print (df) id address place 0 1 11123451 Y 1 2 78947591 X 

РЕДАКТИРОВАТЬ:

Сроки :

N = 1000 :

Если значения saome не находятся в зоне действия, в решениях b и c нет. Проверьте последнюю строку df1 .

 In [73]: %timeit (data1.set_index('id')['address'].apply(f).reset_index()) 1 loop, best of 3: 2.06 s per loop In [74]: %timeit (a(df1a, df2a)) 1 loop, best of 3: 82.2 ms per loop In [75]: %timeit (b(df1b, df2b)) 1 loop, best of 3: 3.17 s per loop In [76]: %timeit (c(df1c, df2c)) 100 loops, best of 3: 2.71 ms per loop 

Код для таймингов :

 np.random.seed(123) N = 1000 data1 = pd.DataFrame({'id':np.arange(1,N+1), 'address': np.random.randint(N*10, size=N)}, columns=['id','address']) #add last row with value out of range data1.loc[data1.index[-1]+1, ['id','address']] = [data1.index[-1]+1, -1] data1 = data1.astype(int) print (data1.tail()) data2 = pd.DataFrame({'lowerbound_address':np.arange(1, N*10,10), 'upperbound_address':np.arange(10,N*10+10, 10), 'place': np.random.randint(40, size=N)}) print (data2.tail()) df1a, df1b, df1c = data1.copy(),data1.copy(),data1.copy() df2a, df2b ,df2c = data2.copy(),data2.copy(),data2.copy() 

 def a(data1, data2): data1['tmp'] = 1 data2['tmp'] = 1 df = pd.merge(data1, data2, on='tmp', how='outer') df = df[(df.lowerbound_address <= df.address) & (df.upperbound_address >= df.address)] df = df.drop(['lowerbound_address','upperbound_address', 'tmp'], axis=1) return (df) 

 def b(data1, data2): places = [] for row1 in data1.itertuples(): for row2 in data2.itertuples(): #print (row1.address) if (row2.lowerbound_address <= row1.address <= row2.upperbound_address): places.append((row1.id, row1.address, row2.place)) df = pd.DataFrame.from_records(places) df.columns=['id','address','place'] return (df) 

 def f(x): #use for ... else for add NaN to values out of range #http://stackoverflow.com/q/9979970/2901002 for row2 in data2.itertuples(): if (row2.lowerbound_address <= x <= row2.upperbound_address): return pd.Series([x, row2.place], index=['address','place']) else: return pd.Series([x, np.nan], index=['address','place']) 

 def c(data1,data2): data1 = data1.sort_values('address') data2 = data2.sort_values('lowerbound_address') df = pd.merge_asof(data1, data2, left_on='address', right_on='lowerbound_address') df = df.drop(['lowerbound_address','upperbound_address'], axis=1) return df.sort_values('id') print (data1.set_index('id')['address'].apply(f).reset_index()) print (a(df1a, df2a)) print (b(df1b, df2b)) print (c(df1c, df2c)) 

Только решение c с merge_asof работает с большим DataFrame :

N=1M :

 In [84]: %timeit (c(df1c, df2c)) 1 loop, best of 3: 525 ms per loop 

Подробнее о слиянии asof в документах .

  • булевая маска в пандах
  • Ошибка при повторении серии Pandas
  • Результат результата sklearn standardcaler отличается от результата вручную
  • Получите процент строк (строк), которые удовлетворяют определенному условию в кадре данных pandas
  • Преобразование категориальных данных в рамку данных панд
  • Расчеты Pandas для печати элементов в окне
  • Я хочу умножить два столбца в pandas DataFrame и добавить результат в новый столбец
  • TfidfVectorizer в scikit-learn: ValueError: np.nan является недопустимым документом
  •  
    Interesting Posts for Van-Lav
    Python - лучший язык программирования в мире.