【问题标题】:np.where iterate through multiple options in conditionals - lengths must match errornp.where 遍历条件中的多个选项 - 长度必须匹配错误
【发布时间】:2020-05-01 16:53:50
【问题描述】:

我希望代码遍历条件中的选项,这样我就不必一遍又一遍地复制和粘贴相同的代码,而只改变条件。

这是我的代码夹:

for row in range(0, len(all_data)):
    all_data['Zone'] = np.where((all_data['Freq'] == [60, 132]) &
                                (all_data['YMD'] == ['2019-11-05 00:00:00', '2019-11-18 00:00:00']) &
                                (all_data['observation'] == ['2', '2']), ['u', 'u'],
                                [all_data['Zone'], all_data['Zone']])

但是,我收到以下错误和回溯:

Traceback(最近一次调用最后一次):文件 "C:\ProgramData\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py", 第 3319 行,在 run_code 中 exec(code_obj, self.user_global_ns, self.user_ns) 文件“”,第 4 行,在 (all_data['YMD'] == ['2019-11-05 00:00:00', '2019-11-18 00:00:00']) & 文件 "C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\ops__init__.py", 第 1179 行,在包装器中 res_values = dispatch_to_index_op(op, self, other, pd.DatetimeIndex) 文件 "C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\ops__init__.py", 第 630 行,在 dispatch_to_index_op 中 结果 = op(left_idx, right) 文件 "C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\indexes\datetimelike.py", 第 132 行,在包装器中 结果 = op(self._data, maybe_unwrap_index(other)) 文件“C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\arrays\datetimes.py”, 第 182 行,在包装器中引发 ValueError("Lengths must match") ValueError: 长度必须匹配

看起来错误是“ValueError:长度必须匹配”。我试图通过复制替换值“u”和替换位置“all_data['Zone']”来修复这个错误,但这显然没有解决问题。 我不确定我哪里出错了或者如何解决这个问题。如果有人有使用 np.where 达到相同目标的替代解决方案,我愿意接受该解决方案。

EDIT1- 添加示例数据

Freq    YMD     Zone    observation

60  10/21/2019     A    1

60  10/21/2019     A    2

60  11/5/2019      A    1

60  11/5/2019      A    2

60  11/18/2019     0    1

60  11/18/2019     0    2

132 10/10/2019     A    2

132 10/21/2019     A    1

132 10/21/2019     A    2

132 11/5/2019      A    1

132 11/5/2019      A    2

132 11/18/2019     A    1

132 11/18/2019     A    2

170 8/31/2019      A    1

170 8/31/2019      N    2

170 9/1/2019       N    1

EDIT2- 添加示例预期输出

Freq    YMD     Zone    observation

60  10/21/2019     A    1

60  10/21/2019     A    2

60  11/5/2019      A    1

60  11/5/2019      u    2

60  11/18/2019     0    1

60  11/18/2019     0    2

132 10/10/2019     A    2

132 10/21/2019     A    1

132 10/21/2019     A    2

132 11/5/2019      A    1

132 11/5/2019      A    2

132 11/18/2019     A    1

132 11/18/2019     u    2

170 8/31/2019      A    1

170 8/31/2019      N    2

170 9/1/2019       N    1

Edit3- 符合目标的笨重代码 这段代码可以满足我的需要,但我不想为每个新的“freq”和“YMD”组合一遍又一遍地复制和粘贴代码。我只想在条件中有一个列表来迭代。即,如果我有 6 种不同的“Freq”和“YMD”组合,我将不得不粘贴代码块 6 次并更改条件。如果有足够的条件组合,它可能会使代码变得很长而且看起来很草率。

all_data['Zone'] = np.where((all_data['Freq'] == 60) &
                            (all_data['YMD'] == '2019-11-05 00:00:00') &
                            (all_data['observation'] == '2'), 'u',
                            all_data['Zone'])
all_data['Zone'] = np.where((all_data['Freq'] == 132) &
                            (all_data['YMD'] == '2019-11-18 00:00:00') &
                            (all_data['observation'] == '2'), 'u',
                            all_data['Zone'])

【问题讨论】:

  • 1.在for 循环中使用np.where 似乎不正确。 2. all_data['Freq'] == [60, 132] 不应该工作,除非您的数据只有 2 行。
  • 好的,我如何让它遍历所有行以查找选项 1 并替换,然后通过选项 X 和替换选项 2。我目前只显示 2 个选项,但理论上,可能还有更多。
  • 当条件只有一个选项并且我需要按顺序更新行和 np.where 时,我使用了 np.where 是 for 循环。具体来说,当条件依赖于前一行时。
  • 请从您的示例数据中添加您的预期输出。
  • 我添加了预期的输出

标签: python-3.x pandas numpy conditional-statements


【解决方案1】:

np.where 正在尝试匹配精确值,这是您的意图吗?您能否发布示例数据,我的假设是其中一个数据框元素的长度不相等(例如,日期可能应该在两个列出的时间之间?而是对照具有 2 个日期元素的列表进行检查)。

(all_data['YMD'] > '2019-11-05 00:00:00' & all_data['YMD'] < '2019-11-18 00:00:00']) &

【讨论】:

  • 我正在尝试匹配精确值。将在几分钟内发布示例数据
  • 我添加了示例数据
  • 谢谢 :) 我认为数据操作将是什么还不是很清楚。你在更新区域吗?您是否尝试替换值?例如all_data['Zone'] = np.where((all_data['Freq'] == [60, 132]) 将立即失败,因为 Freq 具有单个值,并且您试图将其与两个值的列表匹配,因此长度差异。我从您尝试替换的其他评论中看到,所以也许在all_data['Freq'] == [60, 132] 的情况下,您的意思是将值 60 替换为 132?
  • 是的,我需要根据条件更新区域规范,因为自从收集了原始原始数据以来就有新区域,我们不想更改原始数据。
  • 我添加了预期的输出,这可能会解决问题
【解决方案2】:

我认为问题在于同时针对多个值测试Series(数据框列),如(all_data['Freq'] == [60, 132])

制作一个简单的系列:

In [190]: s = pd.Series(['a','b','c','b','d'])                                                   
In [191]: s                                                                                      
Out[191]: 
0    a
1    b
2    c
3    b
4    d
dtype: object

针对一个值进行测试:

In [192]: s=='a'                                                                                 
Out[192]: 
0     True
1    False
2    False
3    False
4    False
dtype: bool

这是一个很好的布尔系列,可以与另一个测试结合使用。您使用 &amp; 来组合不同列上的测试,但我从“笨拙”示例中收集到您想要一个列的 |“或”组合:

In [193]: (s=='a')|(s=='b')                                                                      
Out[193]: 
0     True
1     True
2    False
3     True
4    False
dtype: bool

您在尝试以这种方式进行“或”测试时遇到了问题:

In [194]: s==['a','b']                                                                           
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-194-a889b3de7e64> in <module>
----> 1 s==['a','b']

/usr/local/lib/python3.6/dist-packages/pandas/core/ops/__init__.py in wrapper(self, other, axis)
   1205             # as it will broadcast
   1206             if other.ndim != 0 and len(self) != len(other):
-> 1207                 raise ValueError("Lengths must match to compare")
   1208 
   1209             res_values = na_op(self.values, np.asarray(other))

ValueError: Lengths must match to compare

s 的 5 个值与 RHS 上的 2 个不匹配。

如果您逐行进行测试,它会运行,尽管结果是“与”逻辑,而不是“或”。该行必须匹配两个字符串,但它不能:

In [195]: for row in s: 
     ...:     print(row==['a','b']) 
     ...:                                                                                        
False
False
False
False
False

numpypandas 确实实现了broadcasting,这使我们能够进行更复杂的测试。使用values,从Series派生的numpy数组我可以做到:

In [197]: s.values[:,None]==['a','b']                                                            
Out[197]: 
array([[ True, False],
       [False,  True],
       [False, False],
       [False,  True],
       [False, False]])
In [198]: _.any(axis=1)                                                                          
Out[198]: array([ True,  True, False,  True, False])

Out[193]中相同的真/假序列

复制和粘贴的替代方法是参数化比较:

for a,b,c in [(60,'2019...','2'),(52,'2020...','3')]:
    all_data['Zone'] = np.where((all_data['Freq'] == a) &
                            (all_data['YMD'] == b) &
                            (all_data['observation'] == c), 'u',
                            all_data['Zone'])

【讨论】:

  • 你能为你的解决方案提供一些解释吗?
  • 我明天回到办公室试试这个
  • 抱歉,延迟接受。参数化比较是一个与我预期不同的解决方案,但可以按预期工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-24
  • 2020-05-30
  • 2017-03-25
  • 2023-03-11
  • 2022-06-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多