将列表字典展平为数据框
Flatten of dict of lists into a dataframe
我有一个列表字典说:
data = {'a': [80, 130], 'b': [64], 'c': [58,80]}
我如何将其展平并将其转换为如下所示的数据框:
扁平化字典的一个选项是
flattened_data = {
k + str(i): x
for k, v in data.items()
for i, x in enumerate(v)
}
导致
{'a0': 80, 'a1': 130, 'b0': 64, 'c0': 58, 'c1': 80}
如果您坚持从 1 开始索引,可以使用 enumerate(v, 1)
而不是 enumerate(v)
。如果你想在列表只有一个条目的情况下省略索引,你应该使用 for 循环而不是字典理解。
Imo 你应该首先获得字典根列表和字典叶子列表。
像这样:[a,b,c]
和 [[80,130],[64],[58,80]]
然后用一个循环将它们并行化得到
[a1,a2,b,c1,c2]
和 [80,130,64,58,80]
(这应该只需要几行代码)
然后将其加载到数据框中。
如果您需要更精确的代码,您可以询问:)
使用 pd.DataFrame
构造函数和 GroupBy
+ cumcount
:
data = {'a': [80, 130], 'b': [64], 'c': [58,80]}
df = pd.DataFrame([[k, w] for k, v in data.items() for w in v],
columns=['Index', '0'])
df['Index'] = df['Index'] + (df.groupby('Index').cumcount() + 1).astype(str)
print(df)
Index 0
0 a1 80
1 a2 130
2 b1 64
3 c1 58
4 c2 80
如果不需要计数一个元素列表,请使用 if-else
的嵌套列表理解:
df = pd.DataFrame([('{}{}'.format(k, i), v1)
if len(v) > 1
else (k, v1)
for k, v in data.items()
for i, v1 in enumerate(v, 1)], columns=['Index','Data'])
print (df)
Index Data
0 a1 80
1 a2 130
2 b 64
3 c1 58
4 c2 80
编辑:
data = {'a': [80, 130], 'b': np.nan, 'c': [58,80], 'd':[34]}
out = []
for k, v in data.items():
if isinstance(v, float):
out.append([k, v])
else:
for i, x in enumerate(v, 1):
if len(v) == 1:
out.append([k, x])
else:
out.append(['{}{}'.format(k, i), x])
print (out)
[['a1', 80], ['a2', 130], ['b', nan], ['c1', 58], ['c2', 80], ['d', 34]]
df = pd.DataFrame(out, columns=['Index','Data'])
print (df)
Index Data
0 a1 80.0
1 a2 130.0
2 b NaN
3 c1 58.0
4 c2 80.0
5 d 34.0
另一种方法是使用 from_dict
并将 orient
参数设置为 'index' 和 stack
,最后使用 map
和 format
:
df = pd.DataFrame.from_dict(data, orient='index')
df_out = df.rename(columns=lambda x: x+1).stack()
df_out.index = df_out.index.map('{0[0]}{0[1]}'.format)
print(df_out)
输出:
a1 80.0
a2 130.0
b1 64.0
c1 58.0
c2 80.0
dtype: float64
使用 itertools
和 pd.io._maybe_dedup_names
x = (itertools.product(s[0],s[1]) for s in data.items())
z = [item for z in x for item in z]
df = pd.DataFrame(z).set_index(0)
df.index = pd.io.parsers.ParserBase({'names':df.index})._maybe_dedup_names(df.index)
1
a 80
a.1 130
b 64
c 58
c.1 80
我对 答案的变体很感兴趣
defaultdict
和 count
from collections import defaultdict
from itertools import count
c = defaultdict(lambda:count(1))
{f"{k}{['', next(c[k])][len(V) > 1]}": v for k, V in data.items() for v in V}
{'a1': 80, 'a2': 130, 'b': 64, 'c1': 58, 'c2': 80}
enumerate
{f"{k}{['', i][len(V) > 1]}": v for k, V in data.items() for i, v in enumerate(V, 1)}
{'a1': 80, 'a2': 130, 'b': 64, 'c1': 58, 'c2': 80}
我有一个列表字典说:
data = {'a': [80, 130], 'b': [64], 'c': [58,80]}
我如何将其展平并将其转换为如下所示的数据框:
扁平化字典的一个选项是
flattened_data = {
k + str(i): x
for k, v in data.items()
for i, x in enumerate(v)
}
导致
{'a0': 80, 'a1': 130, 'b0': 64, 'c0': 58, 'c1': 80}
如果您坚持从 1 开始索引,可以使用 enumerate(v, 1)
而不是 enumerate(v)
。如果你想在列表只有一个条目的情况下省略索引,你应该使用 for 循环而不是字典理解。
Imo 你应该首先获得字典根列表和字典叶子列表。
像这样:[a,b,c]
和 [[80,130],[64],[58,80]]
然后用一个循环将它们并行化得到
[a1,a2,b,c1,c2]
和 [80,130,64,58,80]
(这应该只需要几行代码)
然后将其加载到数据框中。
如果您需要更精确的代码,您可以询问:)
使用 pd.DataFrame
构造函数和 GroupBy
+ cumcount
:
data = {'a': [80, 130], 'b': [64], 'c': [58,80]}
df = pd.DataFrame([[k, w] for k, v in data.items() for w in v],
columns=['Index', '0'])
df['Index'] = df['Index'] + (df.groupby('Index').cumcount() + 1).astype(str)
print(df)
Index 0
0 a1 80
1 a2 130
2 b1 64
3 c1 58
4 c2 80
如果不需要计数一个元素列表,请使用 if-else
的嵌套列表理解:
df = pd.DataFrame([('{}{}'.format(k, i), v1)
if len(v) > 1
else (k, v1)
for k, v in data.items()
for i, v1 in enumerate(v, 1)], columns=['Index','Data'])
print (df)
Index Data
0 a1 80
1 a2 130
2 b 64
3 c1 58
4 c2 80
编辑:
data = {'a': [80, 130], 'b': np.nan, 'c': [58,80], 'd':[34]}
out = []
for k, v in data.items():
if isinstance(v, float):
out.append([k, v])
else:
for i, x in enumerate(v, 1):
if len(v) == 1:
out.append([k, x])
else:
out.append(['{}{}'.format(k, i), x])
print (out)
[['a1', 80], ['a2', 130], ['b', nan], ['c1', 58], ['c2', 80], ['d', 34]]
df = pd.DataFrame(out, columns=['Index','Data'])
print (df)
Index Data
0 a1 80.0
1 a2 130.0
2 b NaN
3 c1 58.0
4 c2 80.0
5 d 34.0
另一种方法是使用 from_dict
并将 orient
参数设置为 'index' 和 stack
,最后使用 map
和 format
:
df = pd.DataFrame.from_dict(data, orient='index')
df_out = df.rename(columns=lambda x: x+1).stack()
df_out.index = df_out.index.map('{0[0]}{0[1]}'.format)
print(df_out)
输出:
a1 80.0
a2 130.0
b1 64.0
c1 58.0
c2 80.0
dtype: float64
使用 itertools
和 pd.io._maybe_dedup_names
x = (itertools.product(s[0],s[1]) for s in data.items())
z = [item for z in x for item in z]
df = pd.DataFrame(z).set_index(0)
df.index = pd.io.parsers.ParserBase({'names':df.index})._maybe_dedup_names(df.index)
1
a 80
a.1 130
b 64
c 58
c.1 80
我对
defaultdict
和 count
from collections import defaultdict
from itertools import count
c = defaultdict(lambda:count(1))
{f"{k}{['', next(c[k])][len(V) > 1]}": v for k, V in data.items() for v in V}
{'a1': 80, 'a2': 130, 'b': 64, 'c1': 58, 'c2': 80}
enumerate
{f"{k}{['', i][len(V) > 1]}": v for k, V in data.items() for i, v in enumerate(V, 1)}
{'a1': 80, 'a2': 130, 'b': 64, 'c1': 58, 'c2': 80}