我下面有一个multiIndex的字符串表示形式。
CQRS
我想将表示为 df 的字符串转换回 pandas multiIndex类。熊猫有没有直接可用的功能呢?
例外的输出:
iterables = [['bar', 'baz', 'foo', 'qux'], ['one', 'two']]
df = pd.MultiIndex.from_product(iterables, names=['first', 'second'])
df = str(df)
谢谢。
答案 0 :(得分:2)
MultiIndex的字符串表示几乎是可执行代码,因此您可以使用eval
对其进行评估,如下所示:
eval(df, {}, {'MultiIndex': pd.MultiIndex})
# MultiIndex(levels=[[u'bar', u'baz', u'foo', u'qux'], [u'one', u'two']],
# labels=[[0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 0, 1, 0, 1, 0, 1]],
# names=[u'first', u'second'])
请注意,您必须控制传递给eval
的字符串,因为它可能会导致计算机崩溃和/或运行任意代码(请参阅here和here )。
或者,这是一种安全,简单但有些脆弱的方法:
import ast
# convert df into a literal string defining a dictionary
dfd = (
"{" + df[11:-1] + "}"
.replace("levels=", "'levels':")
.replace("labels=", "'labels':")
.replace("names=", "'names':")
)
# convert it safely into an actual dictionary
args = ast.literal_eval(dfd)
# use the dictionary as arguments to pd.MultiIndex
pd.MultiIndex(**args)
使用此代码,无法使任意字符串使计算机崩溃,因为ast.literal_eval()
不允许任何运算符,仅允许文字表达式。
这是一个安全的版本,不需要预先指定参数名称,但是更复杂:
import ast, tokenize
from cStringIO import StringIO
tokens = [ # make a list of mutable tokens
list(t)
for t in tokenize.generate_tokens(StringIO('{' + df[11:-1] + '}').readline)
]
for t, next_t in zip(tokens[:-1], tokens[1:]):
# convert `identifier=` to `'identifier':`
if t[0] == 1 and next_t[0] == 51 and next_t[1] == '=':
t[0] = 3 # switch type to quoted string
t[1] = "'" + t[1] + "'" # put quotes around identifier
next_t[1] = ':' # convert '=' to ':'
args = ast.literal_eval(tokenize.untokenize(tokens))
pd.MultiIndex(**args)
请注意,如果df
格式错误或在较低级别包含“ identifier = ...”作为代码(不在字符串内),则该代码将引发异常。但我认为str(MultiIndex)
不会发生这种情况。如果出现问题,则可以为原始的ast
字符串生成df
树,然后提取参数并将其以编程方式转换为dict
({{1} },而不是{x: y}
),然后使用dict(x=y)
进行评估。