【问题标题】:Python custom method set to new variable changes old variablePython自定义方法设置为新变量更改旧变量
【发布时间】:2019-09-07 15:49:54
【问题描述】:

我创建了一个具有两种方法的类,NRG_loadNRG_flat。第一个加载 CSV,将其转换为 DataFrame 并应用一些过滤;第二个采用此 DataFrame,并在创建两列后,melts 使用 DataFrame 对其进行旋转。

我正在使用以下代码尝试这些方法:

nrg105 = eNRG.NRG_load('nrg_105a.tsv')
nrg105_flat = eNRG.NRG_flat(nrg105, '105')

其中eNRG 是类,需要“105”作为第二个参数来在方法中运行 if 循环来创建上述列。

我无法解释的行为是第二​​行 - 使用 NRG_flat 方法的行 - 更改了 nrg105 值。

请注意,如果我只运行 NRG_load 方法,我会得到预期的 DataFrame。

我错过了什么行为?因为这不是我第一次应用这样的语法,但我从来没有遇到过问题,所以我不知道我应该看哪里。

提前感谢您的所有建议。

编辑:根据要求,这是班级的代码:

# -*- coding: utf-8 -*-
"""
Created on Tue Apr 16 15:22:21 2019

@author: CAPIZZI Filippo Antonio
"""

import pandas as pd
from FixFilename import FixFilename as ff
from SplitColumn import SplitColumn as sc
from datetime import datetime as ddt


class EurostatNRG:
    # This class includes the modules needed to load and filter
    # the Eurostat NRG files

    # Default countries' lists to be used by the functions
    COUNTRIES = [
        'EU28', 'AL', 'AT', 'BE', 'BG', 'CY', 'CZ', 'DE', 'DK', 'EE', 'EL',
        'ES', 'FI', 'FR', 'GE', 'HR', 'HU', 'IE', 'IS', 'IT', 'LT', 'LU', 'LV',
        'MD', 'ME', 'MK', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SI', 'SK',
        'TR', 'UA', 'UK', 'XK'
    ]

    # Default years of analysis
    YEARS = list(range(2005, int(ddt.now().year) - 1))

    # NOTE: the 'datetime' library will call the current year, but since
    # the code is using the 'range' function, the end years will be always
    # current-1 (e.g. if we are in 2019, 'current year' will be 2018).
    # Thus, I have added "-1" because the end year is t-2.

    INDIC_PROD = pd.read_excel(
        './Datasets/VITO/map_nrg.xlsx',
        sheet_name=[
            'nrg105a_indic', 'nrg105a_prod', 'nrg110a_indic', 'nrg110a_prod',
            'nrg110'
        ],
        convert_float=True)

    def NRG_load(dataset, countries=COUNTRIES, years=YEARS, unit='ktoe'):
        # This module will load and refine the NRG dataset,
        # preparing it to be filtered

        # Fix eventual flags
        dataset = ff.fix_flags(dataset)

        # Load the dataset into a DataFrame
        df = pd.read_csv(
            dataset,
            delimiter='\t',
            encoding='utf-8',
            na_values=[':', ': ', ' :'],
            decimal='.')

        # Clean up spaces from the column names
        df.columns = df.columns.str.strip()

        # Removes the mentioned column because it's not needed
        if 'Flag and Footnotes' in df.columns:
            df.drop(columns=['Flag and Footnotes'], inplace=True)

        # Split the first column into separate columns
        df = sc.nrg_split_column(df)

        # Rename the columns
        df.rename(
            columns={
                'country': 'COUNTRY',
                'fuel_code': 'KEY_PRODUCT',
                'nrg_code': 'KEY_INDICATOR',
                'unit': 'UNIT'
            },
            inplace=True)

        # Filter the dataset
        df = EurostatNRG.NRG_filter(
            df, countries=countries, years=years, unit=unit)

        return df

    def NRG_filter(df, countries, years, unit):
        # This module will filter the input DataFrame 'df'
        # showing only the 'countries', 'years' and 'unit' selected

        # First, all of the units not of interest are removed
        df.drop(df[df.UNIT != unit.upper()].index, inplace=True)

        # Then, all of the countries not of interest are filtered out
        df.drop(df[~df['COUNTRY'].isin(countries)].index, inplace=True)

        # Finally, all of the years not of interest are removed,
        # and the columns are rearranged according to the desired output
        main_cols = ['KEY_INDICATOR', 'KEY_PRODUCT', 'UNIT', 'COUNTRY']
        cols = main_cols + [str(y) for y in years if y not in main_cols]
        df = df.reindex(columns=cols)

        return df

    def NRG_flat(df, name):
        # This module prepares the DataFrame to be flattened,
        # then it gives it as output

        # Assign the indicators and products' names
        if '105' in name:  # 'name' is the name of the dataset
            # Creating the 'INDICATOR' column
            indic_dic = dict(
                zip(EurostatNRG.INDIC_PROD['nrg105a_indic'].KEY_INDICATOR,
                    EurostatNRG.INDIC_PROD['nrg105a_indic'].INDICATOR))
            df['INDICATOR'] = df['KEY_INDICATOR'].map(indic_dic)
            # Creating the 'PRODUCT' column
            prod_dic = dict(
                zip(
                    EurostatNRG.INDIC_PROD['nrg105a_prod'].KEY_PRODUCT.astype(
                        str), EurostatNRG.INDIC_PROD['nrg105a_prod'].PRODUCT))
            df['PRODUCT'] = df['KEY_PRODUCT'].map(prod_dic)
        elif '110' in name:
            # Creating the 'INDICATOR' column
            indic_dic = dict(
                zip(EurostatNRG.INDIC_PROD['nrg110a_indic'].KEY_INDICATOR,
                    EurostatNRG.INDIC_PROD['nrg110a_indic'].INDICATOR))
            df['INDICATOR'] = df['KEY_INDICATOR'].map(indic_dic)
            # Creating the 'PRODUCT' column
            prod_dic = dict(
                zip(
                    EurostatNRG.INDIC_PROD['nrg110a_prod'].KEY_PRODUCT.astype(
                        str), EurostatNRG.INDIC_PROD['nrg110a_prod'].PRODUCT))
            df['PRODUCT'] = df['KEY_PRODUCT'].map(prod_dic)

        # Delete che columns 'KEY_INDICATOR' and 'KEY_PRODUCT', and
        # rearrange the columns in the desired order
        df.drop(columns=['KEY_INDICATOR', 'KEY_PRODUCT'], inplace=True)
        main_cols = ['INDICATOR', 'PRODUCT', 'UNIT', 'COUNTRY']
        year_cols = [y for y in df.columns if y not in main_cols]
        cols = main_cols + year_cols
        df = df.reindex(columns=cols)

        # Pivot the DataFrame to have it in flat format
        df = df.melt(
            id_vars=df.columns[:4], var_name='YEAR', value_name='VALUE')

        # Convert the 'VALUE' column into float numbers
        df['VALUE'] = pd.to_numeric(df['VALUE'], downcast='float')

        # Drop rows that have no indicators (it means they are not in
        # the Excel file with the products of interest)
        df.dropna(subset=['INDICATOR', 'PRODUCT'], inplace=True)

        return df

编辑 2:如果这有帮助,这是我在 IPython 中使用 EurostatNRG 类时收到的错误:

[EurostatNRG 的自动重新加载失败:回溯(最近一次调用最后一次): 文件 "C:\Users\CAPIZZIF\AppData\Local\Continuum\anaconda3\lib\site-packages\IPython\extensions\autoreload.py", 第 244 行,检查中 superreload(m, reload, self.old_objects) 文件 "C:\Users\CAPIZZIF\AppData\Local\Continuum\anaconda3\lib\site-packages\IPython\extensions\autoreload.py", 第 394 行,在超级重载中 update_generic(old_obj, new_obj) 文件 "C:\Users\CAPIZZIF\AppData\Local\Continuum\anaconda3\lib\site-packages\IPython\extensions\autoreload.py", 第 331 行,在 update_generic 更新(a,b)文件“C:\Users\CAPIZZIF\AppData\Local\Continuum\anaconda3\lib\site-packages\IPython\extensions\autoreload.py”, 第 279 行,在 update_class 如果 (old_obj == new_obj) 为真:文件“C:\Users\CAPIZZIF\AppData\Local\Continuum\anaconda3\lib\site-packages\pandas\core\generic.py”, 第 1478 行,在 非零 .format(self.class.name)) ValueError:DataFrame 的真值不明确。使用 a.empty、a.bool()、a.item()、a.any() 或 a.所有()。 ]

【问题讨论】:

  • 我们需要查看类的代码。
  • 正如@brunns 提到的,我们需要检查这些方法。可能NRG_flat 方法正在就地更改第一个参数
  • 试试nrg105_flat = eNRG.NRG_flat(nrg105.copy(), '105')。正如其他人所说,您可能正在就地更改参数
  • 谢谢大家的回复,我已经在原帖中添加了课程代码。
  • 您的类定义使用所有类级别变量。您甚至可以通过类显式调用方法。您需要使用实例变量,并正确定义您的方法以接受self 作为第一个参数。坦率地说,这都是错误的。你应该阅读关于类的文档:docs.python.org/3/tutorial/classes.html

标签: python pandas dataframe


【解决方案1】:

我设法找到了罪魁祸首。

NRG_flat 方法中,行:

df['INDICATOR'] = df['KEY_INDICATOR'].map(indic_dic)
...
df['PRODUCT'] = df['KEY_PRODUCT'].map(indic_dic)

弄乱了df DataFrame 的副本,因此我不得不用Pandas assign method 更改它们:

df = df.assign(INDICATOR=df.KEY_INDICATOR.map(prod_dic))
...
df = df.assign(PRODUCT=df.KEY_PRODUCT.map(prod_dic))

我没有再收到任何错误。

感谢您的回复!

【讨论】:

    猜你喜欢
    • 2022-12-05
    • 1970-01-01
    • 1970-01-01
    • 2022-10-23
    • 2018-03-31
    • 2015-06-14
    • 1970-01-01
    • 1970-01-01
    • 2017-12-08
    相关资源
    最近更新 更多