【问题标题】:pandas equivalent of Stata's encode熊猫相当于Stata的编码
【发布时间】:2014-01-04 08:54:08
【问题描述】:

我正在寻找一种在 Stata 中复制 encode 行为的方法,它将分类字符串列转换为数字列。

x = pd.DataFrame({'cat':['A','A','B'], 'val':[10,20,30]})
x = x.set_index('cat')

结果:

     val
cat     
A     10
A     20
B     30

我想将 cat 列从字符串转换为整数,将每个唯一字符串以 1 对 1 的方式映射到(任意)整数。这将导致:

     val
cat     
1     10
1     20
2     30

或者,同样好:

  cat  val
0   1   10
1   1   20
2   2   30

有什么建议吗?

非常感谢一如既往, 抢

【问题讨论】:

  • 也许:DataFrame([(i[1], i[0]) for i in enumerate(set(x.index))]) 然后合并?
  • 重要细节:这不是 Stata 的encode 所做的。它产生一对一的映射。
  • @NickCox 我不明白这不是一对一的映射。 'A' 的每个实例变成1,'B' 的每个实例变成2 等等。
  • 这不是我在你的例子中看到的。我看到 A、A、B 映射到 10、20、30。为什么第一个 A 得到 10,第二个得到 20?如果那是您想要的,我不明白,但这取决于您;我的观点仍然是 encode 在 Stata 中所做的事情。
  • @NickCox 获取映射的是cat 列,而不是val 列。 val 列保持不变,与示例无关。重要的是 cat 按照我的示例从 ['A','A','B'] 变为 [1,1,2]。

标签: python pandas stata


【解决方案1】:

你可以使用pd.factorize:

import pandas as pd

x = pd.DataFrame({'cat':('A','A','B'), 'val':(10,20,30)})
labels, levels = pd.factorize(x['cat'])
x['cat'] = labels
x = x.set_index('cat')
print(x)

产量

     val
cat     
0     10
0     20
1     30

如果您希望复制 Stata 的行为,可以将 1 添加到 labels:

x['cat'] = labels+1

【讨论】:

  • 获取 [0,0,1] 的另一种方法是查看 pd.Categorical(seq).labels。
  • 谢谢@DSM。查看the source code,我看到Categorical 调用factorize。
  • 谢谢@unutbu。仅供参考:这是制作漂亮的分类散点图的绝妙方法,使用文本列作为类别。
  • @unutbu 这应该在文档中,你能在这里的某个地方做一个 PR:pandas.pydata.org/pandas-docs/dev/…
  • 使用主仓库; stable docs 将在 0.13 发布时更新
【解决方案2】:

Stata 的encode 命令以字符串变量开头,并创建一个新的整数变量,其标签映射到原始字符串变量。 pandas 中的直接模拟现在是分类变量类型,它从 0.15 开始成为 pandas 的成熟部分(在最初询问和回答这个问题后发布)。

请参阅文档here。

为了演示这个例子,Stata 命令应该是这样的:

encode cat, generate(cat2)

而 pandas 命令是:

x['cat2'] = x['cat'].astype('category')

  cat  val cat2
0   A   10    A
1   A   20    A
2   B   30    B

就像 Stata 对 encode 所做的那样,数据以整数形式存储,但在默认输出中显示为字符串。

您可以通过使用分类访问器cat 查看底层整数来验证这一点。 (出于这个原因,您可能不想使用 'cat' 作为列名。)

x['cat2'].cat.codes

0    0
1    0
2    1

【讨论】:

  • 我已经尝试了好几个小时了!正在搜索将对象转换为整数,或将分类转换为数字并发疯。我正在使用 pandas 16.2(当前版本为 anaconda)。
  • +1000 df['a'].cat.codes 是救命稻草!一直在网上搜索以找到使用 sklearn 的 DictVectorizer 或 LabelEncoder 的替代方法。这与 OneHotEncoder 与 sklearn-pandas 完美结合
【解决方案3】:

假设您有一组固定的单个大写英文字母作为分类变量,您也可以这样做:

x['cat'] = x.cat.map(lambda x: ord(x) - 64)

我认为这有点像 hack。但话又说回来,在 Python 中,最好的办法是定义 您 想要的从字符到整数的映射,例如

my_map = {"A":1, ...} 
# e.g.: {x:ord(x)-64  for x in string.ascii_uppercase}
# if that's the convention you happen to desire.

然后做

x['cat'] = x.cat.map(lambda x: my_map[x])

或类似的东西。

这优于依赖内置函数的约定来进行整数映射,原因有很多,而且(IMO)这样的事情对程序员-分析师来说“感觉像是”令人讨厌的转换,但实际上表示有关您正在编写的软件的重要元数据,这暴露了高级语言(如 MATLAB、STATA 等)中全局便利函数的真正弱点。即使有一个内置函数碰巧随机遵守您想要的特定约定使用(“A”映射到 1,“B”映射到 2 等任意约定)使用它并不是一个好主意。

【讨论】:

  • 我将 MATLAB 上的 cmets 留给有经验的用户。 Stata 的 encode 命令上的 cmets 令人费解。它默认按字母顺序将不同的字符串值映射到整数 1,因此“A”、“B”、“C”将映射到 1、2、3。但是可以通过某些指定的字符串到整数转换来覆盖该默认值方案。如果您不想要,请不要使用它;没有明显的语言设计或哲学隐含问题。
  • int64('A') == 65 在 MATLAB 中。 int('A') 在 Python 中引发 ValueError,恕我直言,这更有意义。当然,如果您只在 MATLAB 中编写不与外部世界对话的代码,那么这是一个有争议的问题。
  • @Nick Cox:这完全是设计理念的问题。我有超过 8 年的 MATLAB 使用经验,4 年使用 Python 和 2 年使用 STATA。 STATA 有这样的内置功能并不困扰我,这很好。但是当有人使用该函数为回归中的虚拟变量创建分类变量时,它确实让我感到困扰。这意味着本着this link from The Pragmatic Programmer. 的精神,需要一些元数据(编码)不应该与第三方的东西耦合
  • @Phillip Cloud 我想是否有人期望int 以这种方式行事是一个品味问题。由于 Python 中的 int(x) 只是 x.__int__() 的语法糖,所以我认为它与您不同。我不希望单长度 str 变量具有与多字符 str 变量不同的 __int__ 变量,这为想要像 ord 这样的函数提供了区别,但这只是我的看法。
  • @EMS 您对 Stata 的体验并没有扩展到能够正确拼写其名称或了解 Stata 命令和 Stata 函数之间的区别。如果经验的长度是一个论点,请感受一下我在 Stata 工作的 22 年的重量。更严重,更重要的是,您关于 encode 的 cmets 仍然令人费解,因为您已将您的论点(实际上是一个断言)更改为争辩说如果以您认为可疑的方式使用语言功能就会受到指控。这更多地反映了您的个人品味。
猜你喜欢
  • 2016-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-02
  • 2016-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多