假设我有类别,1到10,我想分配red值3到5,分别green为1,6和7,以及blue分配给2分,8分,9分和10分.
我该怎么做?如果我试试
df.cat.rename_categories(['red','green','blue'])
Run Code Online (Sandbox Code Playgroud)
我收到一个错误:ValueError: new categories need to have the same number of items than the old categories!但是如果我把它放进去的话
df.cat.rename_categories(['green','blue','red', 'red', 'red'
'green', 'green', 'blue', 'blue' 'blue'])
Run Code Online (Sandbox Code Playgroud)
我会收到一个错误,说有重复的值.
我能想到的唯一另一种方法是编写一个for循环,它将遍历值的字典并替换它们.是否有更优雅的解决方案?
不确定优雅,但是如果你制作一个旧到新类别的词典,就像(注意添加的"紫色"):
>>> m = {"red": [3,4,5], "green": [1,6,7], "blue": [2,8,9,10], "purple": [11]}
>>> m2 = {v: k for k,vv in m.items() for v in vv}
>>> m2
{1: 'green', 2: 'blue', 3: 'red', 4: 'red', 5: 'red', 6: 'green',
7: 'green', 8: 'blue', 9: 'blue', 10: 'blue', 11: 'purple'}
Run Code Online (Sandbox Code Playgroud)
您可以使用它来构建新的分类系列:
>>> df.cat.map(m2).astype("category", categories=set(m2.values()))
0 green
1 blue
2 red
3 red
4 red
5 green
6 green
7 blue
8 blue
9 blue
Name: cat, dtype: category
Categories (4, object): [green, purple, red, blue]
Run Code Online (Sandbox Code Playgroud)
categories=set(m2.values())如果您确定在列中可以看到所有分类值,则不需要(如果您关心分类排序,则需要等效的顺序).但是在这里,如果我们不这样做,我们就不会purple在最终的类别中看到它,因为它是从它实际看到的类别构建的.
当然,如果您已经['green','blue','red', etc.]构建了列表,那么使用它直接创建新的分类列并完全绕过此映射也同样容易.
好的,这稍微简单一些,希望能激发进一步的对话。
OP的示例输入:
>>> my_data = {'numbers': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}
>>> df = pd.DataFrame(data=my_data)
>>> df.numbers = df.numbers.astype('category')
>>> df.numbers.cat.rename_categories(['green','blue','red', 'red', 'red'
>>> 'green', 'green', 'blue', 'blue' 'blue'])
Run Code Online (Sandbox Code Playgroud)
这产生了ValueError: Categorical categories must be uniqueOP 状态。
我的解决方案:
# write out a dict with the mapping of old to new
>>> remap_cat_dict = {
1: 'green',
2: 'blue',
3: 'red',
4: 'red',
5: 'red',
6: 'green',
7: 'green',
8: 'blue',
9: 'blue',
10: 'blue' }
>>> df.numbers = df.numbers.map(remap_cat_dict).astype('category')
>>> df.numbers
0 green
1 blue
2 red
3 red
4 red
5 green
6 green
7 blue
8 blue
9 blue
Name: numbers, dtype: category
Categories (3, object): [blue, green, red]
Run Code Online (Sandbox Code Playgroud)
强制你写出一个完整的字典,将旧类别与新类别进行 1:1 映射,但可读性很强。然后转换非常简单:按行使用 df.apply(当在数据系列上使用 .apply 时隐式)获取每个值并将其替换为 remap_cat_dict 中的适当结果。然后将结果转换为类别并覆盖该列。
我几乎遇到了这个问题,我想创建一个新列,其中从旧列转换而来的类别较少,它在这里同样容易工作(并且有益的是不涉及覆盖当前列):
>>> df['colors'] = df.numbers.map(remap_cat_dict).astype('category')
>>> print(df)
numbers colors
0 1 green
1 2 blue
2 3 red
3 4 red
4 5 red
5 6 green
6 7 green
7 8 blue
8 9 blue
9 10 blue
>>> df.colors
0 green
1 blue
2 red
3 red
4 red
5 green
6 green
7 blue
8 blue
9 blue
Name: colors, dtype: category
Categories (3, object): [blue, green, red]
Run Code Online (Sandbox Code Playgroud)
编辑 5/2/20:进一步简化df.numbers.apply(lambda x: remap_cat_dict[x])(df.numbers.map(remap_cat_dict)感谢@JohnE)
似乎pandas.explode与发布的 将适合在那里,因此避免任何循环 -pandas-0.25.0 (July 18, 2019)
# Mapping dict
In [150]: m = {"red": [3,4,5], "green": [1,6,7], "blue": [2,8,9,10]}
In [151]: pd.Series(m).explode().sort_values()
Out[151]:
green 1
blue 2
red 3
red 4
red 5
green 6
green 7
blue 8
blue 9
blue 10
dtype: object
Run Code Online (Sandbox Code Playgroud)
因此,结果是一个 Pandas 系列,其中包含来自values:index. 现在,根据用户的需求,我们可能会直接使用它,或者如果需要以不同的格式使用它,例如 dict 或系列、交换索引和值。让我们也探索一下。
# Mapping obtained
In [152]: s = pd.Series(m).explode().sort_values()
Run Code Online (Sandbox Code Playgroud)
1) 输出为 dict :
In [153]: dict(zip(s.values, s.index))
Out[153]:
{1: 'green',
2: 'blue',
3: 'red',
4: 'red',
5: 'red',
6: 'green',
7: 'green',
8: 'blue',
9: 'blue',
10: 'blue'}
Run Code Online (Sandbox Code Playgroud)
2)输出为系列:
In [154]: pd.Series(s.index, s.values)
Out[154]:
1 green
2 blue
3 red
4 red
5 red
6 green
7 green
8 blue
9 blue
10 blue
dtype: object
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5106 次 |
| 最近记录: |