Pandas: выберите из столбца с индексом, соответствующим значениям в другом столбце - PullRequest
2 голосов
/ 01 апреля 2020

Извиняюсь за дерьмовый заголовок ...

Скажем, у меня есть два pandas кадра данных, касающихся мест отбора проб на местах. DF1 содержит идентификатор образца, координаты, год записи и др. c. DF2 содержит метеорологическую переменную со значениями, указанными в год в виде столбцов:

import pandas as pd
df1 = pd.DataFrame(data = {'ID': [10, 20, 30], 'YEAR': [1980, 1981, 1991]}, index=[1,2,3])
df2 = pd.DataFrame(data= np.random.randint(0,100,size=(3, 10)), columns=['year_{0}'.format(x) for x in range(1980, 1991)], index=[10, 20, 30])

print(df1)
>   ID YEAR
  1 10 1980
  2 20 1981
  3 30 1991

print(df2)
>    year_1980 year_1981 ... year_1990
  10 48 61 ... 53
  20 68 69 ... 21
  30 76 37 ... 70

Обратите внимание, как идентификаторы участков из DF1 соответствуют DF2.index, а также как DF1 лет выборки выходят за пределы охвата DF2. Я хотел бы добавить в качестве нового столбца в DF1 значение из DF2, соответствующее столбцу year в DF1. Пока что у меня есть:

def grab(df, plot_id, yr):
    try:
        out = df.loc[plot_id, 'year_{}'.format(yr)]
    except KeyError:
        out = -99
    return out

df1['meteo_val'] = df1.apply(lambda row: grab(df2, row.index, row.year), axis=1)
print(df1)
>   ID YEAR meteo_val
  1 10 1980 48
  2 20 1981 69 
  3 30 1991 -99   

Это работает, но кажется, что вычисление занимает очень много времени. Мне нужен более разумный и быстрый подход к решению этой проблемы. Есть предложения?

1 Ответ

2 голосов
/ 01 апреля 2020

Настройка

np.random.seed(0)
df1 = pd.DataFrame(data = {'ID': [10, 20, 30], 'YEAR': [1980, 1981, 1991]}, index=[1,2,3])
df2 = pd.DataFrame(data= np.random.randint(0,100,size=(3, 11)),
                   columns=['year_{0}'.format(x) for x in range(1980, 1991)],
                   index=[10, 20, 30])

Решение с DataFrame.lookup:

mapper = df1.assign(YEAR = ('year_' + df1['YEAR'].astype(str)))
c2 = mapper['ID'].isin(df2.index)
c1 = mapper['YEAR'].isin(df2.columns)
mapper = mapper.loc[c1 & c2]
df1.loc[c2&c1, 'meteo_val'] = df2.lookup(mapper['ID'], mapper['YEAR'])
df1 ['meteo_val'] = df1['meteo_val'].fillna(-99)



   ID  YEAR  meteo_val
1  10  1980       44.0
2  20  1981       88.0
3  30  1991      -99.0

Альтернатива с DataFrame.join и DataFrame.stack

df1 = df1.join(df2.set_axis(df2.columns.str.split('_').str[1].astype(int),
                      axis=1).stack().rename('meteo_val'),
               on = ['ID', 'YEAR'], how='left').fillna(-99)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...