Преобразование блока кода в функцию приводит к ошибке - PullRequest
2 голосов
/ 18 июня 2020

Я пытался очистить фрагмент кода, но при переносе части кода в функцию он начал выдвигать мне исключение, см. Ниже:

Вот фрагмент, который я хочу очистить :

import pandas as pd
import os

df = pd.read_csv('winequality-red.csv', sep=';')

labels = list(df.columns)
for index, label in enumerate(labels):
    labels[index] = labels[index].replace(' ', '_')


substance = 'pH'
median = df[substance].mean()
for index, substance in enumerate(df[substance]):
    if substance >= median:
        df.loc[index, substance] = 'high'
    else:
        df.loc[index, substance] = 'low'
print(df.groupby(substance).quality.mean())

Идея состоит в том, чтобы вместо этого создать две функции и вызывать их каждый раз, когда мне нужно оценить вещество, помня об этом:

def substance_mean(substance):
    return df[substance].mean()

def substance_evaluation(substance):
    for index, substance in enumerate(df[substance]):
        if substance >= substance_mean(substance):
            df.loc[index, substance] = 'high'
        else:
            df.loc[index, substance] = 'low'
    print(df.groupby(substance).quality.mean())

substance_evaluation('pH')

Когда я запускал код выбрасывается следующее исключение:

Traceback (most recent call last):
  File "/home/atila/Desktop/estudos/udacity/aws_ML/venv-ml/lib/python3.6/site-packages/pandas/core/indexes/base.py", line 2646, in get_loc
    return self._engine.get_loc(key)
  File "pandas/_libs/index.pyx", line 111, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/index.pyx", line 138, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/hashtable_class_helper.pxi", line 1619, in pandas._libs.hashtable.PyObjectHashTable.get_item
  File "pandas/_libs/hashtable_class_helper.pxi", line 1627, in pandas._libs.hashtable.PyObjectHashTable.get_item
KeyError: 3.51

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/atila/Desktop/estudos/udacity/aws_ML/app.py", line 34, in <module>
    substance_evaluation('pH')
  File "/home/atila/Desktop/estudos/udacity/aws_ML/app.py", line 28, in substance_evaluation
    if substance >= substance_mean(substance):
  File "/home/atila/Desktop/estudos/udacity/aws_ML/app.py", line 24, in substance_mean
    return df[substance].mean()
  File "/home/atila/Desktop/estudos/udacity/aws_ML/venv-ml/lib/python3.6/site-packages/pandas/core/frame.py", line 2800, in __getitem__
    indexer = self.columns.get_loc(key)
  File "/home/atila/Desktop/estudos/udacity/aws_ML/venv-ml/lib/python3.6/site-packages/pandas/core/indexes/base.py", line 2648, in get_loc
    return self._engine.get_loc(self._maybe_cast_indexer(key))
  File "pandas/_libs/index.pyx", line 111, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/index.pyx", line 138, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/hashtable_class_helper.pxi", line 1619, in pandas._libs.hashtable.PyObjectHashTable.get_item
  File "pandas/_libs/hashtable_class_helper.pxi", line 1627, in pandas._libs.hashtable.PyObjectHashTable.get_item
KeyError: 3.51

1 Ответ

1 голос
/ 19 июня 2020

Я не могу запустить его, но вся ваша проблема в том, что внутри substance_evaluation() вы используете одно и то же имя substance для двух переменных, которые должны сохранять разные значения.

Сначала у вас есть substance in

 def substance_evaluation(substance) 

, и эта переменная должна содержать "ph", но позже вы используете

 for ..., substance in ...: 

, которые присваивают другое значение этой переменной (вместо "ph"), а позже вы используете

 ... >= substance_mean(substance) 

для вычисления mean для "ph", но в данный момент substance не имеет значения "ph", а 3.51 ( как показать ошибку KeyError: 3.51)

У вас не было бы этой проблемы, если бы в функции вы сохранили

 median = df[substance].mean()

и

 if substance >= median:

Помимо использования функции для запуска одна строка кода - пустая трата времени.

И, сохраняя эту линию, вы вычисляете медиану только один раз - до l oop. Используя функцию внутри l oop, вы вычисляете одно и то же значение много раз - и это тоже пустая трата времени.


Я думаю, что в обеих версиях (с функцией и без) у вас все еще могут быть проблемы с substance, потому что вы также используете его в df.loc[index, substance], поэтому он может попытаться сделать df.loc[index, 3.51] вместо df.loc[index, "ph"]. Вы должны использовать другое имя ie. value

for ..., value in ...:
    if value >= median:

У вас должна быть одна функция вроде этой:

def substance_evaluation(substance):

    median = df[substance].mean()

    for index, value in enumerate(df[substance]):
        if value >= median:
            df.loc[index, substance] = 'high'
        else:
            df.loc[index, substance] = 'low'

    print(df.groupby(substance).quality.mean())

Но я думаю, вы могли бы написать ее просто.

def substance_evaluation(substance):

    median = df[substance].mean()

    mask = (df[substance] >= mediam)

    df[substance][  mask ] = 'high'
    df[substance][ ~mask ] = 'low'

    print(df.groupby(substance).quality.mean())

В итоге с np.where()

def substance_evaluation(substance):

    median = df[substance].mean()

    mask = (df[substance] >= mediam)

    df[substance] = np.where(mask, 'high', 'low')

    print(df.groupby(substance).quality.mean())

В этой версии вы можете легко создать новый столбец со значениями

    df["new column"] = np.where(mask, 'high', 'low')

РЕДАКТИРОВАТЬ: Минимальный рабочий код для теста

import pandas as pd
import random
import numpy as np
import time

def version1(df, substance):
    median = df[substance].mean()
    for index, value in enumerate(df[substance]):
        if value >= median:
            df.loc[index, substance] = 'high'
        else:
            df.loc[index, substance] = 'low'

def version2(df, substance):
    median = df[substance].mean()
    mask = (df[substance] >= median)
    df[substance][  mask ] = 'high'
    df[substance][ ~mask ] = 'low'

def version3(df, substance):
    median = df[substance].mean()
    mask = (df[substance] >= median)
    df[substance] = np.where(mask, 'high', 'low')

# ---

random.seed(0) # to generate always the same values

df = pd.DataFrame({'pH': [random.randint(0,7) for _ in range(5)]})

substance = 'pH'

print('--- before ---')
print(df)

# ---

df1 = df.copy()
start = time.time()

version1(df1, substance)

end = time.time()
print('--- after --- time:', end-start)
print(df1)

# ---

df2 = df.copy()
start = time.time()

version2(df2, substance)

end = time.time()
print('--- after --- time:', end-start)
print(df1)

# ---

df3 = df.copy()
start = time.time()

version3(df3, substance)

end = time.time()
print('--- after --- time:', end-start)
print(df1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...