【问题标题】:Creating a DataFrame in a For Loop Produces Nan Error在 For 循环中创建 DataFrame 会产生 Nan 错误
【发布时间】:2021-01-14 23:20:02
【问题描述】:

在 Jupyter Notebook 上探索 Olympics 数据集时,我试图从 this dataset 中找出最古老的运动。

这是我目前拥有的代码:


sports = olympics.set_index('Sport')
sport_name = olympics['Sport'].unique()

for sport in sport_name:
    years_played = sports.loc[sport, ['Year']].max() - sports.loc[sport, ['Year']].min()
    print(sport, years_played)

代码返回这个结果:

Basketball Year    80.0
dtype: float64
Judo Year    52.0
dtype: float64
Boxing Year    112.0
dtype: float64

Here's a screenshot to the output.

注意每个浮点数前面都有一个字符串“Year”。

然后我尝试使用以下代码将其转换为 DataFrame:

sports = olympics.set_index('Sport')
sport_name = olympics['Sport'].unique()

for sport in sport_name:
    years_played = sports.loc[sport, ['Year']].max() - sports.loc[sport, ['Year']].min()
    rows = []
    rows = rows.append([sport, years_played])
    pd.DataFrame(rows, columns = ['Sport', 'Years Played'])

返回错误:KeyError: nanHere's a screenshot to the error.

我有两个问题:

  1. 为什么循环在每个浮点结果之前返回一个字符串“Year”?我尝试在循环外使用同一行代码(使用.loc,然后用.min() 减去.max()),结果之前没有字符串,只有结果浮点数。
  2. 是什么导致了nan 错误?

非常感谢。

【问题讨论】:

    标签: python pandas indexing jupyter-notebook


    【解决方案1】:

    嗨,kim,欢迎来到 StackOverflow。我会尽力解释得更好。

    问题 1

    循环以这种格式返回结果:

    dtype: int64
    Basque Pelota Year    0
    
    dtype: int64
    Aeronautics 0
    

    如您所见,Basque Pelota Year 0 包含 YearAeronautics 0 没有。

    在第一种情况下years_played 的类型是<class 'pandas.core.series.Series'>,但在第二种情况下是<class 'numpy.int64'>。这意味着在第一种情况下,您必须访问该系列的值,例如:years_played['Year'],但在第二种情况下,如果您尝试这样做,它将引发异常 IndexError: invalid index to scalar variable.,因为它是 int64 类型而不是系列.

    在您的情况下,检查years_played 的类型并根据类型获取值就足够了:

    print(sport, years_played['Year'] if isinstance(years_played, Series) else years_played)
    

    查看built-in function isinstance() 的参考。您也可以使用type() function 避免使用type(),因为它只是返回对象的类型,而isinstance() 如果对象参数是classinfo 参数的实例,则返回true,或者(直接、间接或虚拟)的子类。

    最终代码

    基本上最终的代码会产生这样的结果:

    import pandas as pd
    from pandas.core.series import Series
    
    olympics = pd.read_csv("athlete_events.csv")
    
    sports = olympics.set_index('Sport')
    sport_name = olympics['Sport'].unique()
    
    for sport in sport_name:
        years_played = sports.loc[sport, ['Year']].max() - sports.loc[sport, ['Year']].min()
        print(type(years_played)) 
        print(sport, years_played['Year'] if isinstance(years_played, Series) else years_played)
    

    解决问题的另一种方法可能是在开始时解决类型问题:

    import pandas as pd
    from pandas.core.series import Series
    
    olympics = pd.read_csv(r"C:\Users\carlo.zanocco\Desktop\archive\athlete_events.csv")
    
    sports = olympics.set_index('Sport')
    sport_name = olympics['Sport'].unique()
    
    for sport in sport_name:
        years_played = sports.loc[sport, 'Year'].max() - sports.loc[sport, 'Year'].min()
        print(type(years_played)) 
        print(sport, years_played)
    

    这里我把sports.loc[sport, ['Year']].max() - sports.loc[sport, ['Year']].min()改成了sports.loc[sport, 'Year'].max() - sports.loc[sport, 'Year'].min(),所以它只会返回<class 'numpy.int64'>类型的值,打印结果时不需要检查类型。

    问题 2

    错误KeyError: nan 表示您正在尝试访问不存在的密钥。在你的情况下,密钥nan

    基本上这个异常映射了未找到的键。

    【讨论】:

    • 感谢您的帮助和及时回复,@Carlo Zanocco。是什么导致 Aeronautics 和 Basque Pelota 的课程类型存在差异?
    • 问题在第二种方案中说明,使用sports.loc[sport, 'Year'].max() - sports.loc[sport, 'Year'].min()对齐类型为<class 'numpy.int64'>。问题是您使用['Year'] 创建了一个系列
    • @kim 如果此答案或任何答案解决了您的问题,请单击复选标记考虑accepting it。这向更广泛的社区表明您已经找到了解决方案,并为回答者和您自己提供了一些声誉。没有义务这样做。
    【解决方案2】:

    天哪,我明白为什么这很难调试了。您的输出屏幕截图中缺少的是最后一部分

    Year    80
    dtype: int64
    Year    52
    dtype: int64
    ...
    Year    12
    dtype: int64
    Year    0
    dtype: int64
    0
    

    请注意最后一行如何不遵循其余的模式!如果您在循环结束时检查sportyears_played,似乎没有任何问题。但是如果你检查

    • sports.loc[sport[0], ['Year']]
    • sports.loc[sport[-1], ['Year']]

    比较它们你会发现发生了什么。

    第一个是DataFrame。您会看到它被一个名为Sport 的索引索引,其中的每个条目都是Basketball。像这样:

                Year
    Sport           
    Basketball  1992
    Basketball  2008
    Basketball  1952
    Basketball  2000
    Basketball  1972
    ...          ...
    Basketball  2004
    Basketball  1996
    Basketball  2004
    Basketball  2008
    Basketball  2016
    
    [4536 rows x 1 columns]
    

    然而,第二个是一个系列:

    Year    1936
    Name: Aeronautics, dtype: object
    

    ...如果您从 DataFrame 中选择 only 一行,就会得到这样的结果。

    我怀疑你已经知道这一点 - 我注意到你将 'Year' 包装在一个列表中,这确保你在第一种情况下得到一个 DataFrame。只有一列称为Year,所以如果你不这样做,你会得到一个系列:

    sports.loc[sport, 'Year'] ->
    
    Sport
    Basketball    1992
    Basketball    2008
    Basketball    1952
    Basketball    2000
    Basketball    1972
                  ... 
    Basketball    2004
    Basketball    1996
    Basketball    2004
    Basketball    2008
    Basketball    2016
    Name: Year, Length: 4536, dtype: int64
    

    (找出与之前输出的差异)

    现在,如果您执行sports.loc["Aeronautics", "Year"],您只会返回一个整数1936,因为您选择了一个单元格。这会导致错误,因为 int 没有您的代码所期望的 maxmin 方法。

    一种解决方案是强制它始终返回一个 DataFrame。你可以这样做......

    for sport in sport_name:
        data = sports.loc[[sport], ['Year']]
        years_played = data.max() - data.min()
        print(sport, years_played)
    

    ...但这只是使您的问题的真正原因变得明显,而不是解决它。现在data.max() - data.min()回来了

    Year    0
    dtype: int64
    

    这是一个熊猫系列,只有一个条目。 Series 的索引是 "Year"(因为那是上面创建的 DataFrame data 的列名)。这就是为什么你得到奇怪的输出。实际修复很简单 - 只需选择单个值,现在我们已经确保我们将总是得到一个系列:

    for sport in sport_name:
        data = sports.loc[[sport], ['Year']]
        years_played = data.max() - data.min()
        print(sport, years_played[0])
    

    您发布的第二段代码将永远无法工作:

    for sport in sport_name:
        years_played = sports.loc[sport, ['Year']].max() - sports.loc[sport, ['Year']].min()
        rows = []
        rows = rows.append([sport, years_played])
        pd.DataFrame(rows, columns = ['Sport', 'Years Played'])
    

    最后一行从您放入列表的单行创建一个新的 DataFrame,但没有将其分配给任何东西。但是,就我而言,它也不会引发错误,因此我怀疑我的 pandas (v1.1.0) 版本与您的行为不同。无论如何,我敢肯定,问题将是相同的:years_played 要么是 Series 要么是 int,这取决于这项运动是否已经进行了多年。

    【讨论】:

      猜你喜欢
      • 2018-12-09
      • 1970-01-01
      • 1970-01-01
      • 2016-08-09
      • 2021-04-04
      • 2018-07-08
      • 2013-09-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多