Pandas преобразование списка переменных в макеты в более широкий фрейм данных - PullRequest
1 голос
/ 02 февраля 2020

Я импортировал файл json, и теперь у меня есть фрейм данных, в котором один столбец (код) является списком.

index year   gvkey    code
0    1998    15686    ['TAX', 'ENVR', 'HEALTH']
1    2005    15372    ['EDUC', 'TAX', 'HEALTH', 'JUST']
2    2001    27486    ['LAB', 'TAX', 'HEALTH']
3    2008    84967    ['HEALTH','LAB', 'JUST']

То, что я хочу получить, выглядит следующим образом:

index year   gvkey  TAX  ENVR HEALTH EDUC JUST LAB
0    1998    15686   1     1     1    0    0    0
1    2005    15372   1     0     1    0    1    0
2    2001    27486   1     0     1    0    1    0
3    2008    84967   0     0     1    0    1    1

После Pandas преобразовать столбец списка в макеты Я попробовал следующий код (где df - мой фрейм данных):

s = pd.Series(df["code"])
l = pd.get_dummies(s.apply(pd.Series).stack()).sum(level=0)

Я получаю вторая часть права данных (переменные TAX, ENVR, HEALTH, EDU C, JUST и LAB), но потеря первой (year и gvkey).

Как сохранить переменную year и gvkey?

Ответы [ 2 ]

4 голосов
/ 02 февраля 2020

Я думаю, что лучшим решением здесь является использование DataFrame.pop с Series.str.join и Series.str.get_dummies:

df = df.join(df.pop('code').str.join('|').str.get_dummies())
print (df)
       year  gvkey  EDUC  ENVR  HEALTH  JUST  LAB  TAX
index                                                 
0      1998  15686     0     1       1     0    0    1
1      2005  15372     1     0       1     1    0    1
2      2001  27486     0     0       1     0    1    1
3      2008  84967     0     0       1     1    1    0

Если важна производительность MultiLabelBinarizer:

from sklearn.preprocessing import MultiLabelBinarizer

mlb = MultiLabelBinarizer()
df1 = pd.DataFrame(mlb.fit_transform(df.pop('code')),columns=mlb.classes_)

df = df.join(df1)
print (df)
       year  gvkey  EDUC  ENVR  HEALTH  JUST  LAB  TAX
index                                                 
0      1998  15686     0     1       1     0    0    1
1      2005  15372     1     0       1     1    0    1
2      2001  27486     0     0       1     0    1    1
3      2008  84967     0     0       1     1    1    0

Ваше решение возможно, , но медленно , поэтому лучше избегайте его, также sum работает только для уникальных значения, для общего решения нужно max:

df = df.join(pd.get_dummies(df.pop('code').apply(pd.Series).stack()).max(level=0))
print (df)
       year  gvkey  EDUC  ENVR  HEALTH  JUST  LAB  TAX
index                                                 
0      1998  15686     0     1       1     0    0    1
1      2005  15372     1     0       1     1    0    1
2      2001  27486     0     0       1     0    1    1
3      2008  84967     0     0       1     1    1    0
2 голосов
/ 02 февраля 2020

Это можно сделать следующими способами:

Метод 1: преобразовать столбец в кадр данных и получить пустышки, затем groupby на axis=1 и получить максимум:

m = pd.get_dummies(pd.DataFrame(df['code'].tolist())).groupby(lambda x:
    x.split('_')[1],axis=1).max()
final1 = df.drop('code',1).assign(**m)

Способ 2: объедините список столбцов с помощью | и используйте series.str.get_dummies

final2 = df.drop('code',1).assign(**df['code'].str.join('|').str.get_dummies())

Метод 3: Ваш метод с concat

s = pd.Series(df["code"])
l = pd.get_dummies(s.apply(pd.Series).stack()).max(level=0)
final3 = pd.concat((df.drop('code',1),l),axis=1)
#or final = df.drop('code',1).assign(**l)
...