【问题标题】:How do I iterate through a dataframe using nested for loop using python2.7 and append to a new dataframe column?如何使用 python2.7 使用嵌套 for 循环遍历数据框并附加到新的数据框列?
【发布时间】:2018-06-14 19:43:43
【问题描述】:

我正在尝试遍历两个 python 数据框列以确定特定值,然后将结果添加到新列。下面的代码抛出以下错误:

raise ValueError('Length of values does not match length of ' 'index')" 

我不知道为什么?

数据框:

    TeamID    todayorno
1   sw        True
2   pr        False
3   sw        False
4   pr        True

代码:

team = []

for row in results['TeamID']:   
    if row == "sw":
        for r in results['todayorno']:
            if r == True:
                team.append('red')
            else:
                team.append('green')
    else:
        team.append('green')

results['newnew'] = team  

【问题讨论】:

  • 您提供了一个示例,说明数据框在代码运行之前的外观。您能否举例说明您希望数据框如何您的代码运行后查看?

标签: python python-2.7 pandas dataframe


【解决方案1】:

您正在迭代数据框两次,这表明您有 2 个 for 循环。您最终会得到 10 个项目的结果,而不是所需的 4 个。

不需要显式迭代。您可以使用numpy.select 为指定条件应用值。

import numpy as np

mask = results['TeamID'] == 'sw'
conditions = [~mask, mask & results['todayorno'], mask & ~results['todayorno']]
values = ['green', 'red', 'green']

results['newnew'] = np.select(conditions, values, 'green')

print(results)

  TeamID  todayorno newnew
1     sw       True    red
2     pr      False  green
3     sw      False  green
4     pr       True  green

【讨论】:

  • 谢谢jpp!这完全按预期工作。我将阅读 numpy ! :D
  • 你能解释一下这条线是如何工作的吗? conditions = [~mask, mask & results['todayorno'], mask & ~results['todayorno']] ---- 让我戳一下:你选择的是所有的反面掩码,今天的掩码和掩码逆向选择 todayorno?然后分配与绿色,红色,绿色相同的顺序?
  • ~ 表示否定,& 表示“和”或“交集”。 conditions 的每一项都与values 中的一项相匹配。例如,~mask 匹配 'green'(每个列表中的第一个元素)。
【解决方案2】:

快速解答

不要尝试循环。

相反,使用默认值(即最常见的)创建新列,然后处理要更改的值并设置它们:

>>> results
  TeamID  todayorno
0     sw       True
1     pr      False
2     sw      False
3     pr       True
>>> results['newnew'] = 'green'
>>> results
  TeamID  todayorno newnew
0     sw       True  green
1     pr      False  green
2     sw      False  green
3     pr       True  green
>>> results.loc[(results['TeamID'] == 'sw') & (results['todayorno']), 'newnew'] = 'red'
>>> results
  TeamID  todayorno newnew
0     sw       True    red
1     pr      False  green
2     sw      False  green
3     pr       True  green

或者,您可以使用.apply(..., index=1) 来计算整个系列,并使用一个查看每一行的函数,并将整个系列一次性分配为一列:

>>> results
  TeamID  todayorno
0     sw       True
1     pr      False
2     sw      False
3     pr       True
>>> results['newnew'] = results.apply(
...     lambda s: 'red' if s['TeamID'] == 'sw' and s['todayorno'] else 'green',
...     axis=1,
... )
>>> results
  TeamID  todayorno newnew
0     sw       True    red
1     pr      False  green
2     sw      False  green
3     pr       True  green

说明

问题

据我从您的代码中可以看出,您正在尝试向数据框中添加一个名为 newnew 的列。

TeamID 列包含值"sw" 和列todayorno 包含值True 的数据框行中,您希望列newnew 包含值"red"

在所有其他行中,您希望newnew 的值为"green"

规则

要高效地使用 pandas,一条非常重要的规则是:不要尝试循环。尤其是通过行。

而是让 pandas 为您完成这项工作。

因此,第一步是创建新列。由于在大多数情况下您希望值为"green",您可以简单地执行以下操作:

results['newnew'] = 'green'

现在你的数据框看起来像:

  TeamID  todayorno newnew
0     sw       True  green
1     pr      False  green
2     sw      False  green
3     pr       True  green

您会注意到 pandas “扩展”了通过所有行提供的单个值。

现在要将sw/True 行变为"red",首先您需要找到所有这些行。为此,我们需要了解 pandas 寻址的工作原理。

(一点点)pandas 寻址的工作原理

当您在 pandas 数据框后使用方括号时,通常是在处理数据框的列。例如:

>>> results['TeamID']
0    sw
1    pr
2    sw
3    pr
Name: TeamID, dtype: object

即通过请求results 数据帧的TeamID 索引,您将返回一个名为TeamIDSeries,其中仅包含该列的值。

另一方面,如果要寻址行,则需要使用.loc 属性。

>>> results.loc[1]
TeamID          pr
todayorno    False
newnew       green
Name: 1, dtype: object

这里我们得到了一个包含行值的Series

如果我们想查看多行,我们可以通过索引行列表来获得一个子数据框:

>>> results.loc[[1,2]]
  TeamID  todayorno newnew
1     pr      False  green
2     sw      False  green

或者通过使用条件:

>>> results.loc[results['TeamID'] == 'pr']
  TeamID  todayorno newnew
1     pr      False  green
3     pr       True  green

条件可以包含布尔组合,但其语法有特殊要求,例如使用 & 而不是 and 并且由于 & 运算符的优先级而小心地将条件部分用括号括起来:

>>> results.loc[(results['TeamID'] == 'sw') & (results['todayorno'])]
  TeamID  todayorno newnew
1     sw       True  green

.loc 属性也可以按行和列寻址。逗号分隔寻址部分,其中行的寻址在前,列在后:

>>> results.loc[results['TeamID'] == 'pr', 'todayorno']
1    False
3     True
Name: todayorno, dtype: bool

最后的润色

.loc 属性也可用于赋值,方法是将您想要的值分配给所需的“坐标”。

所以在你的情况下:

>>> results.loc[
...     (results['TeamID'] == 'sw') & (results['todayorno']),
...     'newnew'
... ] = "red"
>>> results
  TeamID  todayorno newnew
0     sw       True    red
1     pr      False  green
2     sw      False  green
3     pr       True  green

另一种解决方案

.apply() 数据帧方法允许多次应用单个函数,无论是按列还是按行。要逐行应用,请传递 axis=1 参数。

如果传递给.apply(..., axis=1)的函数的结果返回单个值,那么该函数的每个应用的结果将组合成一个具有相同寻址(相同index,用 pandas 的说法)数据帧的行。

所以:

>>> results.apply(
...     lambda s: 'red' if s['TeamID'] == 'sw' and s['todayorno'] else 'green',
...     axis=1,
... )
0      red
1    green
2    green
3    green
dtype: object

然后可以将其分配为数据框的列:

>>> results['newnew'] = results.apply(
...     lambda s: 'red' if s['TeamID'] == 'sw' and s['todayorno'] else 'green',
...     axis=1,
... )
>>> results
  TeamID  todayorno newnew
0     sw       True    red
1     pr      False  green
2     sw      False  green
3     pr       True  green

【讨论】:

  • 注意pd.Series.apply + lambda 应该作为一个最后的手段在矢量化解决方案是不可能的情况下使用。使用布尔序列进行索引比逐行三元语句更有效。
猜你喜欢
  • 2020-08-09
  • 1970-01-01
  • 2019-08-20
  • 2018-05-30
  • 2021-06-13
  • 2021-07-29
  • 2018-07-20
  • 2018-10-28
  • 1970-01-01
相关资源
最近更新 更多