Поэлементное умножение pandas на индексы

#python #pandas #dataframe

#python #pandas #фрейм данных

Вопрос:

У меня есть два фрейма данных df1 и df2 :

 df1 = pd.DataFrame({"a" : [1,2,3,4,5,6,7,8,9,10,11,12],
                    "b" : [-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12],
                    "t" : [1,2,3,4,5,6,7,8,9,10,11,12]})
df1.index = [1,1,1,2,2,2,3,3,3,4,4,5]

df2 = pd.DataFrame({"a" : [10,20,30],
                    "b" : [-10,-20,-30]})
df2.index = [2,3,4]
  

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

 df1
    a   b   t
1   1  -1   1
1   2  -2   2
1   3  -3   3
2   4  -4   4
2   5  -5   5
2   6  -6   6
3   7  -7   7
3   8  -8   8
3   9  -9   9
4  10 -10  10
4  11 -11  11
5  12 -12  12

df2
    a   b
2  10 -10
3  20 -20
4  30 -30
  

Таким образом, столбцы df2 являются подмножеством столбцов df1 . Я хочу умножить строки df1 на строки df2 , где они имеют одинаковый индекс, и сохранить только те строки, которые состоят из пересечения между их индексами, т. Е. в основном

 ls_keep = []
for i in range(len(df1)):
    for j in range(len(df2)):
        if df1.index[i] == df2.index[j]:
            df1.iloc[i]["a"] = df1.iloc[i]["a"] * df2.iloc[j]["a"]
            df1.iloc[i]["b"] = df1.iloc[i]["b"] * df2.iloc[j]["b"]
            ls_keep.append(i)

df1 = df1.iloc[ls_keep]
  

Это дает мне

      a    b   t
2   40   40   4
2   50   50   5
2   60   60   6
3  140  140   7
3  160  160   8
3  180  180   9
4  300  300  10
4  330  330  11
  

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

Ответ №1:

Сначала отфильтруйте только совпадающие индексы в new DataFrame с помощью boolean indexing и isin , а затем умножьте на mul with df2.columns для обработки одинаковых столбцов в обоих DataFrame s:

 df11 = df1[df1.index.isin(df2.index)].copy()
df11[df2.columns] = df11[df2.columns].mul(df2)
print (df11)
     a    b   t
2   40   40   4
2   50   50   5
2   60   60   6
3  140  140   7
3  160  160   8
3  180  180   9
4  300  300  10
4  330  330  11