运行下面的示例代码时,我得到一个
ValueError: cannot set using a multi-index selection indexer with a different
length than the value
执行时出现错误
df.loc[(9, 0), ("clouds", "type")] = np.array([None, None])
这里:
~\Anaconda3\lib\site-packages\pandas\core\indexing.py in _setitem_with_indexer(self, indexer, value)
492
493 if len(obj[idx]) != len(value):
--> 494 raise ValueError
问题似乎与将 numpy 数组写入数据帧的“单元格”有关。看来 obj[idx] 引用了数据帧中的索引 (20,),而它应该引用 (9,0)。执行时在引发错误的迭代之前进行几次迭代
df.loc[(6, 0), ("clouds", "type")] = np.array([None, None])
没有错误被引发,因为巧合obj[idx]
引用了数据帧中的索引(17,),它有2个子索引,所以偶然len(obj[idx ])==len(值)==2
.
备注:
当我阅读时
df.loc[(9, 0), ("clouds", "type")].values
它正确返回[104]
。
问题:
我是否错误地使用了.loc
函数?我还做错了什么吗?或者这是 pandas 内部的问题?我怎样才能避免它?
我非常感谢任何帮助,因为这个问题让我困扰了几天:/
代码:
import pandas as pd
import numpy as np
mi = pd.MultiIndex(levels=[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]],
labels=[[0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7, 8, 9, 10, 10, 11, 12, 12, 13, 14, 14,
14, 15, 16, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 22],
[0, 1, 0, 1, 2, 3, 0, 1, 2, 0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 2, 0, 0,
0, 1, 0, 1, 2, 0, 1, 2, 3, 0, 1, 2, 0, 1, 2, 0, 1, 2]])
mc = pd.MultiIndex(levels=[['clouds', 'group', 'header', 'vertical_visibility', 'visibility', 'weather', 'wind', 'windshear'],
['', 'BR', 'DS', 'DU', 'DZ', 'FC', 'FG', 'FU', 'GR', 'GS', 'HZ', 'IC', 'PL', 'PO', 'PY', 'RA', 'SA', 'SG', 'SN', 'SQ', 'SS', 'UP', 'VA', 'altitude', 'ceiling', 'direction', 'form', 'from_date', 'from_hours', 'from_minutes', 'gust', 'icao_code', 'layer', 'more', 'origin_date', 'origin_hours', 'origin_minutes', 'probability', 'range', 'speed', 'till_date', 'till_hours', 'till_minutes', 'type', 'unit', 'valid_from_date', 'valid_from_hours', 'valid_till_date', 'valid_till_hours'],
['bool', 'intensity', 'modifier']],
labels=[[0, 0, 0, 1, 1, 1],
[24, 32, 43, 27, 28, 29],
[-1, -1, -1, -1, -1, -1]])
arr = np.array(range(0,len(mi)*len(mc))).reshape(len(mi),len(mc))
df = pd.DataFrame(arr, index=mi, columns=mc)
values = {0: {0: [None]}, 1: {0: [None], 1: [None], 2: [None], 3: [None]}, 2: {0: [None], 2: [None]}, 3: {0: [None], 1: [None], 2: [None], 3: [None], 4: [None], 5: [None]}, 4: {0: [None]}, 6: {0: [None, None]}, 9: {0: [None, None]}}
for i, val in values.items():
for j, v in val.items():
df.loc[(i,j),("clouds", "type")] = np.array(v)
最佳答案
("clouds", "type", None)
列具有整数数据类型:
In [28]: df[("clouds", "type", None)].dtype
Out[28]: dtype('int64')
因此,如果要将 NumPy 数组分配给此列,请首先将 dtype 更改为 object
:
df[("clouds", "type", None)] = df[("clouds", "type", None)].astype('object')
- 使用
df.at
或df.iat
选择 DataFrame 的特定单元格或为其赋值。 - 使用
df.loc
或df.iloc
选择列、行或子 DataFrame 或为其赋值。
因此,请在此处使用df.at
:
df[("clouds", "type", None)] = df[("clouds", "type", None)].astype('object')
for i, val in values.items():
for j, v in val.items():
df.at[(i, j), ("clouds", "type", None)] = np.array(v)
这会产生一个 df
,看起来像
clouds group
ceiling layer type from_date from_hours from_minutes
NaN NaN NaN NaN NaN NaN
0 0 0 1 [None] 3 4 5
1 6 7 8 9 10 11
1 0 12 13 [None] 15 16 17
1 18 19 [None] 21 22 23
2 24 25 [None] 27 28 29
3 30 31 [None] 33 34 35
2 0 36 37 [None] 39 40 41
1 42 43 44 45 46 47
2 48 49 [None] 51 52 53
3 0 54 55 [None] 57 58 59
1 60 61 [None] 63 64 65
2 66 67 [None] 69 70 71
3 72 73 [None] 75 76 77
4 78 79 [None] 81 82 83
5 84 85 [None] 87 88 89
4 0 90 91 [None] 93 94 95
5 0 96 97 98 99 100 101
6 0 102 103 [None, None] 105 106 107
7 0 108 109 110 111 112 113
8 0 114 115 116 117 118 119
9 0 120 121 [None, None] 123 124 125
...
关于the comment您希望将云/类型列用于分类数据:
包含分类数据的列必须包含可哈希值。一般来说,让可变对象可哈希是没有意义的。因此,例如,Python 可变内置函数(例如列表)或 NumPy 数组是不可散列的。但 Python 不可变内置函数(例如元组)是可哈希的。因此,如果您使用
df.at[(i, j), ("clouds", "type", None)] = tuple(v)
然后您可以将 category
的 ("clouds", "type", None)
列设置为 dtype:
df[("clouds", "type", None)] = df[("clouds", "type", None)].astype('object')
for i, val in values.items():
for j, v in val.items():
df.at[(i, j), ("clouds", "type", None)] = tuple(v)
df[("clouds", "type", None)] = df[("clouds", "type", None)].astype('category')
注意,需要先将object
列设为dtype,使其可以包含元组等Python对象,之后才转换为category
dtype可能的值已被分配。
根据您想要对数据执行的操作,"tidy" the data 也可能更有意义。通过仅将字符串分配给clouds/type列并使用多行而不是元组:
例如,
6 0 102 103 'foo' 105 106 107
6 0 102 103 'bar' 105 106 107
而不是
6 0 102 103 ('foo', 'bar') 105 106 107
使用多行的一个优点是选择具有云/类型的所有行 'foo' 现在很容易:
df.loc[df[("clouds", "type", None)] == 'foo']
或选择带有 foo
或 bar
cloud/type 的所有行:
df.loc[df[("clouds", "type", None)].isin(['foo', 'bar'])]
如果您使用元组,则必须使用类似的内容
df.loc[[any(kind in item for kind in ('foo', 'bar'))
for item in df[("clouds", "type", None)]]]
请注意,这只是更长、更难阅读,而且速度也更慢。
使用多行的一个缺点是它会创建重复的数据,这可能需要更多的内存使用。可能有解决这个问题的方法,例如使用多个表(并且仅在需要时连接它们),但对此的讨论将远远超出本问题的范围。
所以综上所述,一般来说,使用tidy data ,使用多行,并保持 DataFrame 数据类型简单——尽可能使用整数、 float ,必要时使用“字符串”。尽量避免使用元组、列表或 NumPy 数组作为 DataFrame 值。
关于python - pandas loc 函数在写入和读取时引用不同的行 -> ValueError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53262460/