Панды: создать длинный / аккуратный DataFrame из словаря, когда значения являются наборами или списками переменной длины - PullRequest
0 голосов
/ 03 октября 2018

Простой словарь:

d = {'a': set([1,2,3]), 'b': set([3, 4])}

(наборы могут быть превращены в списки, если это имеет значение)

Как преобразовать его в long / tidy DataFrame, в котором каждый столбецявляется переменной, и каждое наблюдение является строкой, то есть:

  letter  value
0      a      1
1      a      2
2      a      3
3      b      3
4      b      4

Следующее работает, но немного громоздко:

id = 0
tidy_d = {}
for l, vs in d.items():
    for v in vs:
        tidy_d[id] = {'letter': l, 'value': v}
        id += 1
pd.DataFrame.from_dict(tidy_d, orient = 'index')

Есть ли какая-нибудь магия pandas, чтобы сделать это?Что-то вроде:

pd.DataFrame([d]).T.reset_index(level=0).unnest()

, где unnest явно не существует и происходит от R.

Ответы [ 4 ]

0 голосов
/ 18 июня 2019

Чуть более "панда", вдохновленный этой записью:

pd.DataFrame.from_dict(d, orient = 'index') \
  .rename_axis('letter').reset_index() \
  .melt(id_vars = ['letter'], value_name = 'value') \
  .drop('variable', axis = 1) \
  .dropna()
0 голосов
/ 03 октября 2018

Вы можете использовать понимание с itertools.chain и zip:

from itertools import chain

keys, values = map(chain.from_iterable, zip(*((k*len(v), v) for k, v in d.items())))

df = pd.DataFrame({'letter': list(keys), 'value': list(values)})

print(df)

  letter  value
0      a      1
1      a      2
2      a      3
3      b      3
4      b      4

Это может быть переписано более читабельным способом:

zipper = zip(*((k*len(v), v) for k, v in d.items()))
values = map(list, map(chain.from_iterable, zipper))

df = pd.DataFrame(list(values), columns=['letter', 'value'])
0 голосов
/ 03 октября 2018

Просто еще один,

from collections import defaultdict
e = defaultdict(list)
for key, val in d.items():
    e["letter"] += [key] * len(val)
    e["value"] += list(val)
df = pd.DataFrame(e)
0 голосов
/ 03 октября 2018

Использование numpy.repeat с chain.from_iterable:

from itertools import chain

df = pd.DataFrame({
    'letter' : np.repeat(list(d.keys()), [len(v) for k, v in d.items()]),
    'value' : list(chain.from_iterable(d.values())), 
})
print (df)
  letter  value
0      a      1
1      a      2
2      a      3
3      b      3
4      b      4
...