pandas apply () функция без необходимости возвращать значение? / быстрый цикл через DF? - PullRequest
0 голосов
/ 01 апреля 2020

У меня большая (~ 145000 строк) база данных рецептов, над которой я работаю. У меня есть столбец 'parsed_ingredients', который выглядит следующим образом (несколько диктов на строку):

[{'orig_name': '1,00 kg Kalbsbraten ',
  'orig_amount': '1.00',
  'orig_unit': 'kg',
  'amount': 0.25,
  'unit': 'g',
  'splitted_ingredient': 'Kalbsbraten',
  'splitted_slized_ingredient': 'Kalbsbraten',
  'further_specification': '',
  'alternatives': '',
  'matched_ingredient_id': 'U030100',
  'matched_ingredient_st': 'Kalb Hackfleisch roh',
  'calorie': 148,
  'protein': 19.726,
  'carb': 0.0,
  'fat': 7.713},
 {'orig_name': '1,00  Zwiebel(n) ',
  'orig_amount': '1.00',
  'orig_unit': 'Anzahl',
  'amount': 9.0,
  'unit': 'g',
  'splitted_ingredient': 'Zwiebel(n)',
  ...
]

По сути, я пытаюсь подготовить свой df для элемента и пользователя (на основе контента) Рекомендую систему, поэтому я пытаюсь создать матрицу со столбцом для каждого ингредиента, содержащегося в рецепте.

Я пробовал следующее, но у меня была проблема, что это просто очень медленно с таким большим количеством rows:

for index, row in df.iterrows():
    extracted_ingredient = ""
    for ingredient in row["parsed_ingredients"]:
        extracted_ingredient = ingredient["matched_ingredient_st"]
        if not extracted_ingredient == "None":
            df.loc[index, extracted_ingredient] = 1

Поэтому я попытался написать функцию для использования с apply, так как я читал, что она вычисляется намного быстрее, но потом понял, что apply всегда хочет, чтобы я возвратил что-то для сохранения в DF (в противном случае я получаю 'TypeError: объект' NoneType 'не может быть вызван':

def ingredient_extraction(content, dataframe=df):
    for newrow in content:
        for entry in newrow:
            if not entry["matched_ingredient_st"] == "None":
                df[entry["matched_ingredient_st"]] = 1

df.apply(ingredient_extraction(df["parsed_ingredients"], df), axis=1)

Можно ли как-нибудь заставить pandas применить эту функцию к моему df независимо от этого? Или есть лучший способ ускорить операцию сделано в iterrows?

Ответы [ 2 ]

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

Просто грубый набросок идеи.

Допустим, у вас есть DataFrame, например, так:

recipe_id | parsed_ingredients
------------------------------
 1        | [{...}, {...}, ...]
 2        | [{...}, {...}, ...]
 3        | [{...}, {...}, ...]

Используя метод explode, разверните DataFrame, чтобы в нем отображался один словарь ингредиентов. row.

df = df.explode('parsed_ingredients')
df.head()

recipe_id | parsed_ingredients
------------------------------
 1        | {...}
 1        | {...}
     ...
 2        | {...}
 2        | {...}
     ...
 3        | {...}
 3        | {...}
     ...

Теперь извлеките matched_ingredient_st из каждого из словарей

df['matched_ingredient_st'] = df['parsed_ingredients'].apply(lambda x: x['matched_ingredient_st'])
df['match'] = 1 # Added for the next step
df.head()

recipe_id | parsed_ingredients | matched_ingredient_st | match
--------------------------------------------------------------
 1        | {...}              | ingredient_a          | 1
 1        | {...}              | ingredient_b          | 1
     ...
 2        | {...}              | ingredient_b          | 1
 2        | {...}              | ingredient_d          | 1
     ...
 3        | {...}              | ingredient_c          | 1
 3        | {...}              | ingredient_d          | 1
     ...

Теперь вы можете использовать встроенный метод сводки, чтобы уменьшить DataFrame до аналогичного формата в исходный набор данных

df = df.pivot(index='recipe_id ', columns='matched_ingredient_st ', values='match')
df.head()

   | ingredient_a | ingredient_b | ingredient_c | ingredient_d 
---------------------------------------------------------------
 1 |       1      |       1      |       0      |       0      |
 2 |       0      |       1      |       0      |       1      |
 3 |       0      |       0      |       1      |       1      |

На самом деле это не запустилось в Python, но есть лог c и методы есть.

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

Сначала вы можете сгенерировать все значения в списках словарей, а затем перейти к конструктору DataFrame, последнее присоединение к оригиналу:

L = [[{'matched_ingredient_id': 'U030100',
  'matched_ingredient_st': 'Kalb',
},
 {  'matched_ingredient_id': 'U030100',
  'matched_ingredient_st': 'Ka',
  'splitted_ingredient': 'Zwiebel(n)'}],[
  {'matched_ingredient_id': 'U030100',
  'matched_ingredient_st': 'roh',
},
 {  'matched_ingredient_id': 'U030100',
  'matched_ingredient_st': 'K',
  'splitted_ingredient': 'Zwiebel'}
]]

df = pd.DataFrame({'parsed_ingredients':L})

L = [{y['matched_ingredient_st']:1 for y in x if not y["matched_ingredient_st"] == "None"}
      for x in df['parsed_ingredients']]


df1 = pd.DataFrame(L, index=df.index).fillna(0).astype(int)
print (df1)
   Kalb  Ka  roh  K
0     1   1    0  0
1     0   0    1  1

df = df.join(df1)
print(df)
                                  parsed_ingredients  Kalb  Ka  roh  K
0  [{'matched_ingredient_id': 'U030100', 'matched...     1   1    0  0
1  [{'matched_ingredient_id': 'U030100', 'matched...     0   0    1  1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...