【问题标题】:Operation across observations and year is returned NaN跨观测值和年份的操作返回 NaN
【发布时间】:2019-12-25 05:42:38
【问题描述】:

我有一个面板数据集,其中包含一组国家 [意大利和美国] 3 年和两个数字变量 ['Var1', 'Var2']。我想计算最近三年的变化率 例如:2019 年 Var1 的值减去 2017 年 Var1 的值除以 2017 年的 Var1。

我不明白为什么我的代码(如下)返回 NaN 错误?

data = {'Year':[2017, 2018, 2019, 2017, 2018, 2019], 'Country':['Italy', 'Italy', 'Italy', 'US' ,  'US', 'US'], 'Var1':[23,75,45, 32,13,14], 'Var2':[21,75,47, 30,11,18]}
trend = pd.DataFrame(data) 
list = ['Var1', 'Var2']
for col in list:
    trend[col + ' (3 Year % Change)'] = ((trend.loc[trend['Year']==2019][col]- trend.loc[trend['Year']==2017][col])/trend.loc[trend['Year']==2017][col])*100

trend

【问题讨论】:

  • 您希望每年与 2017 年相比吗?还是上一年?

标签: python pandas return panel


【解决方案1】:

检查这是否提供了您想要的。它更容易理解。

trend['Var1_3_Year_%_Change'] = trend.groupby('Country')['Var1'].apply(lambda x : ((x-x.iloc[0]))/x.iloc[0]*100)
trend['Var2_3_Year_%_Change'] = trend.groupby('Country')['Var2'].apply(lambda x : ((x-x.iloc[0]))/x.iloc[0]*100)
trend['Var1_yearly'] = trend.groupby('Country')['Var1'].apply(lambda x : ((x-x.shift()))/x.shift()*100)
trend['Var2_yearly'] = trend.groupby('Country')['Var2'].apply(lambda x : ((x-x.shift()))/x.shift()*100)

输出

Year    Country     Var1    Var2    Var1_3_Year_%_Change    Var2_3_Year_%_Change    Var1_yearly     Var2_yearly
2017    Italy   23  21  0.000000    0.000000    NaN     NaN
2018    Italy   75  75  226.086957  257.142857  226.086957  257.142857
2019    Italy   45  47  95.652174   123.809524  -40.000000  -37.333333
2017    US  32  30  0.000000    0.000000    NaN     NaN
2018    US  13  11  -59.375000  -63.333333  -59.375000  -63.333333
2019    US  14  18  -56.250000  -40.000000  7.692308    63.636364

如果必须使用for循环,请使用

var= ['Var1','Var2']
for col in var:
trend[col + ' (3 Year % Change)'] = trend.groupby('Country')[col].apply(lambda x : ((x-x.iloc[0]))/x.iloc[0]*100)

【讨论】:

  • 这很好,它会起作用,但在现实生活中我有几个数字变量(不仅仅是 to)。我试过你用循环方法,但它给了我一个错误:ValueError:错误的项目数量传递了 2,放置意味着 1 ..如何解决它?
  • 这适用于任意数量的行。 (x-x.iloc[0]) 是当前行和第一行(同一列)之间的差异,因此无论行数如何,它都可以工作。与x-x.shift() 相同,这是当前行中的值与上一行中的值之间的差异。这也将与任何数量的行无关。
【解决方案2】:

您的代码存在一些问题:

  1. 您正在尝试除法pd.series,不仅是它们的数组,而且它们带有索引,这导致除法变为NaN
  2. 如果您实际传递值,例如在列过滤器之后使用.values,您将遇到ValueError,因为您希望将两个值插入整个DataFrame,而pandas 不会像那样(长度应该相同)。这就是例证:
trend.loc['Var1' + ' (3 Year % Change)'] = ((trend.loc[trend['Year']==2019, 'Var1'].values - \
                                        trend.loc[trend['Year']==2017, 'Var1'].values)/\
                                        trend.loc[trend['Year']==2017, 'Var1'].values)*100

ValueError: 无法设置列不匹配的行

  1. 不确定您是否使用list 作为实际变量名,但这是一个保留的python 字。这不是最好的主意。你可以阅读它here

如果要将值与样本中的 2017 值进行比较,可以使用 groupby+shift,根据要轮班多少年:

for col in ['Var1','Var2']:
    trend[col + ' (3 Year % Change)'] = (trend[col] - trend.groupby('Country').shift(2)[col])/trend.groupby('Country').shift(2)[col]

Out[1]:
   Year Country  Var1  Var2  Var1 (3 Year % Change)  Var2 (3 Year % Change)
0  2017   Italy    23    21                     NaN                     NaN
1  2018   Italy    75    75                     NaN                     NaN
2  2019   Italy    45    47                0.956522                1.238095
3  2017      US    32    30                     NaN                     NaN
4  2018      US    13    11                     NaN                     NaN
5  2019      US    14    18               -0.562500               -0.400000

【讨论】:

  • 谢谢,成功了!并感谢您的解释,非常有帮助
猜你喜欢
  • 1970-01-01
  • 2023-04-03
  • 2023-03-23
  • 2021-10-29
  • 2017-10-13
  • 2018-06-17
  • 1970-01-01
  • 1970-01-01
  • 2021-01-29
相关资源
最近更新 更多