系列中的字典列表映射到pandas数据帧

时间:2018-01-30 21:16:40

标签: python python-3.x pandas

我有一个如下数据框:

data = {'name': {0: 'mypath\\is\this', 1: 'mynewpath\\is\this'},
        'vals': {0: [{'name1': 'val1'}, {'name2': 'val2'}, {'name3': 'val3'}],
                 1: [{'name1': 'val1'}, {'name2': 'val2'}, {'name3': 'val3'}]}}
df = pd.DataFrame(data)

name                       vals
mypath\is\this             [{name1:val1},{name2:val2},{name3:val3}]
mynewpath\is\this          [{name1:val1},{name2:val2},{name3:val3}]

如何展开values列并将键映射到创建新名称,以保持与其相关的值。

预期输出如下:

name                    vals
mypath\is\this\name1    val1
mypath\is\this\name2    val2
mypath\is\this\name3    val3
mynewpath\is\this\name1 val1
mynewpath\is\this\name2 val2
mynewpath\is\this\name3 val3

3 个答案:

答案 0 :(得分:1)

首先使用最少示例的解决方案:

import pandas as pd

df = pd.DataFrame({
   "name": ["mypath\is\this", "mynewpath\is\this"],
    "vals":[[{"name1":"val1"},{"name2":"val2"},{"name3":"val3"}], [{"name1":"val1"},{"name2":"val2"},{"name3":"val3"}]]
})

解决方案包括将每个行中的dict列表拆分为带有该段代码的DataFrame:

df = pd.DataFrame({
        "name":
        row["name"],
        "key": [element for d in row["vals"] for element in list(d.keys())],
        "value":
        [element for d in row["vals"] for element in list(d.values())]
    })

然后juste concatenate并操纵字符串以获得所需的输出。

这里有完整的代码:

df = pd.concat([
    pd.DataFrame({
        "name":
        row["name"],
        "key": [element for d in row["vals"] for element in list(d.keys())],
        "value":
        [element for d in row["vals"] for element in list(d.values())]
    }) for index, row in df.iterrows()
])
df["name"] = df["name"] + "\\" + df["key"]
df = df.drop("key", axis=1)

注1:我放\\因为\是一个espace字符。

注2:我使用list comprehension迭代数据帧的行,这样可以更容易地连接所有数据帧。

答案 1 :(得分:1)

我真的想尝试一下矢量化解决方案。但是df.vals是一系列的词汇而不仅仅是一系列的词汇让我失望。希望我们看到其他一些人有更好的解决方案。

在最上面的列表中,这是我设法得到的。你可能会发现它很有用。请注意,这并没有利用矢量化,因为我在行轴上使用了apply。

>>> df
                name                                               vals
0     mypath\is\this  [{'name1': 'val1'}, {'name2': 'val2'}, {'name3...
1  mynewpath\is\this  [{'name1': 'val1'}, {'name2': 'val2'}, {'name3...
>>> def explode_column(row):
...     for column in row.vals:
...             for key,value in column.items():
...                     row[key] = value
...     return row
...
>>> exploded_df = df.apply(explode_column, axis=1)
>>> exploded_df
                name                                               vals name1 name2 name3
0     mypath\is\this  [{'name1': 'val1'}, {'name2': 'val2'}, {'name3... val1  val2  val3
1  mynewpath\is\this  [{'name1': 'val1'}, {'name2': 'val2'}, {'name3... val1  val2  val3
>>> melted_df = exploded_df.melt(id_vars=['name'], value_vars=['name1', 'name2', 'name3'])
>>> melted_df
                name variable value
0     mypath\is\this    name1  val1
1  mynewpath\is\this    name1  val1
2     mypath\is\this    name2  val2
3  mynewpath\is\this    name2  val2
4     mypath\is\this    name3  val3
5  mynewpath\is\this    name3  val3
>>> melted_df['new_name'] = melted_df.name.str.cat(melted_df.variable, sep="\\")
>>> melted_df
                name variable value                 new_name
0     mypath\is\this    name1  val1     mypath\is\this\name1
1  mynewpath\is\this    name1  val1  mynewpath\is\this\name1
2     mypath\is\this    name2  val2     mypath\is\this\name2
3  mynewpath\is\this    name2  val2  mynewpath\is\this\name2
4     mypath\is\this    name3  val3     mypath\is\this\name3
5  mynewpath\is\this    name3  val3  mynewpath\is\this\name3

答案 2 :(得分:1)

因为我们将Python对象作为值,所以矢量化解决方案似乎不可行。使用列表理解是有道理的:

df = pd.DataFrame([('\\'.join((r[1]['name'], list(x.keys())[0])), list(x.values())[0]) 
                  for r in df.iterrows() for x in r[1]['vals']], columns=['name', 'vals'])
print(df)

输出:

                      name  vals
0     mypath\is\this\name1  val1
1     mypath\is\this\name2  val2
2     mypath\is\this\name3  val3
3  mynewpath\is\this\name1  val1
4  mynewpath\is\this\name2  val2
5  mynewpath\is\this\name3  val3