J'ai les données suivantes:

study_id       list_value
1              ['aaa', 'bbb']
1              ['aaa']
1              ['ccc']
2              ['ddd', 'eee', 'aaa']
2              np.NaN
2              ['zzz', 'aaa', 'bbb']

Comment puis-je le convertir en quelque chose comme ça?

study_id       list_value
1              ['aaa', 'bbb', 'ccc']
1              ['aaa', 'bbb', 'ccc']
1              ['aaa', 'bbb', 'ccc']
2              ['aaa', 'bbb', 'ddd', 'eee', 'zzz'] 
2              ['aaa', 'bbb', 'ddd', 'eee', 'zzz'] 
2              ['aaa', 'bbb', 'ddd', 'eee', 'zzz'] # order of list item doesn't matter
4
KubiK888 12 avril 2018 à 23:57

4 réponses

Meilleure réponse

itertools.chain avec GroupBy.transform
Tout d'abord, débarrassez-vous des NaN dans votre colonne en utilisant une compréhension de liste (désordonné, je sais, mais c'est le moyen le plus rapide de le faire).

df['list_value'] = [
    [] if not isinstance(x, list) else x for x in df.list_value
]

Ensuite, groupez sur study_id et aplatissez vos listes dans GroupBy.transform et extrayez des valeurs uniques à l'aide d'un set.

from itertools import chain

df['list_value'] = df.groupby('study_id').list_value.transform(
    lambda x: [list(set(chain.from_iterable(x)))]
)

Comme dernière étape, si vous prévoyez de muter des éléments de liste individuels, vous voudrez peut-être faire

df['list_value'] = [x[:] for x in df['list_value']]

Si ce n'est pas le cas, les modifications d'une liste seront répercutées sur toutes les sous-listes de ce groupe.

df
   study_id                 list_value
0         1            [aaa, ccc, bbb]
1         1            [aaa, ccc, bbb]
2         1            [aaa, ccc, bbb]
3         2  [bbb, ddd, eee, aaa, zzz]
4         2  [bbb, ddd, eee, aaa, zzz]
5         2  [bbb, ddd, eee, aaa, zzz]
5
cs95 12 avril 2018 à 21:31

C'est une façon manuelle.

import pandas as pd, numpy as np
from itertools import chain

df = pd.DataFrame({'study_id': [1, 1, 1, 2, 2, 2],
                   'list_value': [['aaa', 'bbb',], ['aaa'], ['ccc'],['ddd', 'eee', 'aaa'],
                                  np.nan, ['zzz', 'aaa', 'bbb']]})

counts = df['study_id'].value_counts()

grp = df.dropna(subset=['list_value'])\
        .groupby('study_id')['list_value']\
        .apply(lambda x: sorted(set(chain.from_iterable(x))))\
        .reset_index()

res = pd.concat([pd.concat([grp[grp['study_id'] == x]]*counts[x]) for x in counts.index])\
        .sort_values('study_id')\
        .reset_index(drop=True)

#    study_id                 list_value
# 0         1            [aaa, bbb, ccc]
# 1         1            [aaa, bbb, ccc]
# 2         1            [aaa, bbb, ccc]
# 3         2  [aaa, bbb, ddd, eee, zzz]
# 4         2  [aaa, bbb, ddd, eee, zzz]
# 5         2  [aaa, bbb, ddd, eee, zzz]
4
jpp 12 avril 2018 à 21:28

defaultdict

from collections import defaultdict

d = defaultdict(set)

for t in df.dropna(subset=['list_value']).itertuples():
    d[t.study_id] |= set(t.list_value)

df.assign(list_value=df.study_id.map(pd.Series(d).apply(sorted)))


   study_id       list_value
0         1        [a, b, c]
1         1        [a, b, c]
2         1        [a, b, c]
3         2  [a, b, d, e, z]
4         2  [a, b, d, e, z]
5         2  [a, b, d, e, z]

np.unique et autres autres ruses

Attention, les résultats sont ndarray

df.assign(
    list_value=df.study_id.map(
        df.set_index('study_id').list_value.dropna().sum(level=0).apply(np.unique)
    )
)

   study_id       list_value
0         1        [a, b, c]
1         1        [a, b, c]
2         1        [a, b, c]
3         2  [a, b, d, e, z]
4         2  [a, b, d, e, z]
5         2  [a, b, d, e, z]

Nous devons utiliser sorted pour y arriver

df.assign(
    list_value=df.study_id.map(
        df.set_index('study_id').list_value.dropna()
          .sum(level=0).apply(np.unique).apply(sorted)
    )
)

Gross Way!

df.assign(
    list_value=df.study_id.map(
        df.list_value.str.join('|').groupby(df.study_id).apply(
            lambda x: sorted(set('|'.join(x.dropna()).split('|')))
        )
    )
)

   study_id       list_value
0         1        [a, b, c]
1         1        [a, b, c]
2         1        [a, b, c]
3         2  [a, b, d, e, z]
4         2  [a, b, d, e, z]
5         2  [a, b, d, e, z]

Installer

df = pd.DataFrame(dict(
    study_id=[1, 1, 1, 2, 2, 2],
    list_value=[['a', 'b'], ['a'], ['c'], ['d', 'e', 'a'], np.nan, ['z', 'a', 'b']]
), columns=['study_id', 'list_value'])
5
piRSquared 12 avril 2018 à 21:43

Remplissez votre valeur nulle avec une liste vide, puis utilisez transform

df.at[df.list_value.isnull().nonzero()[0][0],'list_value']=[]

df.groupby('study_id').list_value.transform(lambda x : [list(set(x.sum()))])
Out[160]: 
0          [b, c, a]
1          [b, c, a]
2          [b, c, a]
3    [b, e, d, z, a]
4    [b, e, d, z, a]
5    [b, e, d, z, a]
Name: list_value, dtype: object
4
YOBEN_S 13 avril 2018 à 00:57