Разделите разрыв списка в столбце на строки и несколько меток для пересечения - PullRequest
2 голосов
/ 11 февраля 2020

Task1

предполагаемый набор данных

    Name    B   C
0   James   a   a,b,c,d
1   James   a   NaN
2   Rudy    b   a,f
3   Karl    c   e,c

В столбце c значения представлены в виде списка, и я хочу разделить их и добавить их в ряд. Удалите значение, столбец которого C равен NaN

выходное значение, которое я хочу

    Name    B   C
0   James   a   a
1   James   a   b
2   James   a   c
3   James   a   d
4   Rudy    b   a
5   Rudy    b   f
6   Karl    c   e
7   Karl    c   c

Task2

I хотел бы пометить, основываясь на отношениях между Джеймсом, Руди, Карлом и столбцом 'C'.

Стандарт маркировки ( среднее пересечение)

Label    column 'C' value
 0       James  
 1       Rudy   
 2       Karl   
 3       James ∩ Rudy   
 4       James ∩ Karl       
 5       Rudy ∩ Karl        
 6       James ∩ Rudy ∩ Karl

Я хочу пометить в зависимости от того, где находится каждое значение 'C'. Label logic

Окончательный результат отражает то, что я хочу

    Name    B   C   Label
0   James   a   a   3
1   James   a   b   0
2   James   a   c   4
3   James   a   d   0
4   Rudy    b   a   3
5   Rudy    b   f   1
6   Karl    c   e   2
7   Karl    c   c   4

Например, 'a' в столбце 'C' помечен 3, потому что это в Джеймсе и Руди

Трудно для меня. Буду признателен, если вы мне поможете.

Спасибо, что прочитали.

Ответы [ 3 ]

1 голос
/ 11 февраля 2020

Первая часть использования DataFrame.explode с DataFrame.dropna и DataFrame.reset_index с drop=True для индекса по умолчанию:

#if values are lists
df1 = df.explode('C').dropna(subset=['C']).reset_index(drop=True)
#if values are separated by , add split
#df1 = df.assign(C = df['C'].str.split(',')).explode('C').dropna(subset=['C']).reset_index(drop=True)
print (df1)
    Name  B  C
0  James  a  a
0  James  a  b
0  James  a  c
0  James  a  d
2   Rudy  b  a
2   Rudy  b  f
3   Karl  c  e
3   Karl  c  c

Затем создайте второй DataFrame с помощью хэшируемых set s, называемых frozenset s, поэтому порядок значений не важен:

#https://stackoverflow.com/a/5898031
from itertools import chain, combinations
def all_subsets(ss):
    return chain(*map(lambda x: combinations(ss, x), range(1, len(ss)+1)))

L = [(i, frozenset(x)) for i, x in enumerate(all_subsets(df['Name'].unique()))]
df2 = pd.DataFrame(L, columns=['Label','C'])
print (df2)
   Label                    C
0      0              (James)
1      1               (Rudy)
2      2               (Karl)
3      3        (Rudy, James)
4      4        (James, Karl)
5      5         (Rudy, Karl)
6      6  (Rudy, James, Karl)

И для второго создания Series с DataFrame.set_index , который используется для Series.map для добавления frozenset с и затем для добавления Label с:

s = df2.set_index('C')['Label']
df["Label"] = df['C'].map(df.groupby('C')['Name'].apply(frozenset)).map(s)
print (df)

    Name  B  C  Label
0  James  a  a      3
1  James  a  b      0
2  James  a  c      4
3  James  a  d      0
4   Rudy  b  a      3
5   Rudy  b  f      1
6   Karl  c  e      2
7   Karl  c  c      4
1 голос
/ 11 февраля 2020
import pandas as pd
import numpy as np

df = pd.DataFrame({'Name':['James', 'James', 'Rudy','Karl'],
                   'B':['a','a','b','c'],
                   'C':[['a','b','c','d'], np.nan, ['a','f'], ['e','c']]})

# Task 1
df = df.explode(column='C').reset_index(drop=True)
df.dropna(inplace=True)


# Task 2
labels = {'James'                :0,
          'Rudy'                 :1,
          'Karl'                 :2,
          'James ∩ Rudy'         :3,
          'James ∩ Karl'         :4,
          'Karl ∩ Ruby'          :5,
          'James ∩ Karl ∩ Rudy'  :6}

C_to_labels = df.groupby('C')['Name'].apply(lambda x: labels[' ∩ '.join(sorted(x))])
df['Label'] = df['C'].map(C_to_labels)

Результат:

    Name  B  C  Label
0  James  a  a      3
1  James  a  b      0
2  James  a  c      4
3  James  a  d      0
4   Rudy  b  a      3
5   Rudy  b  f      1
6   Karl  c  e      2
7   Karl  c  c      4
1 голос
/ 11 февраля 2020

Для задачи 1, если данные в столбцах C перечислены, как вы сказали, вы можете использовать разнесение.

df.explode('C').dropna()

    Name    B   C
0   James   a   a
0   James   a   b
0   James   a   c
0   James   a   d
2   Rudy    b   a
2   Rudy    b   f
3   Karl    c   e
3   Karl    c   c

Для задачи 2 не совсем понятен лог c.

...