Реструктурируйте фрейм данных (может быть, как pivot или unvivot), чтобы каждый столбец отображал метку данных, основанную на 0 и 1 - PullRequest
1 голос
/ 05 апреля 2020

У меня есть данные опроса. Опрос задает вопрос, и респонденты выбирают одну или несколько категорий для каждого вопроса. Затем опрос задает демографические c вопросы, такие как пол. Выходные данные представляют собой фрейм данных с демографической информацией c в виде столбцов и матриц 0 и 1 для каждой категории в каждом вопросе (0 = не выбран и 1 = выбран).

Чтобы помочь вам лучше понять, как это Похоже, у меня есть следующий фрейм данных:

df = pd.DataFrame({'Survey ID': [1,2,3],
                   'Q1_Topic A': [0,1,1], 
                   'Q1_Topic B': [1,0,1], 
                   'Q1_Topic C': [1,0,0],
                   'Q2_Topic X': [0,0,1], 
                   'Q2_Topic Y': [0,1,0], 
                   'Q2_Topic Z': [0,0,1],
                   'Gender': ['Male', 'Female', 'Male']
                  })
print(df)

Мне нужно преобразовать этот фрейм данных, чтобы показать мне столбец для каждого вопроса и несколько строк для каждого опроса в зависимости от того, сколько категорий было выбрано. В каждой строке должна быть категория под соответствующим столбцом с вопросом.

Все еще не уверены? Трудно объяснить, но данные должны выглядеть следующим образом:

df2 = pd.DataFrame({'Survey ID': [1,1,2,3,3],
                   'Q1': ['B','C','A','A','B'], 
                   'Q2': [float('nan'), float('nan'), 'Y', 'X', 'Z'],
                   'Gender': ['Male', 'Male', 'Female', 'Male', 'Male']
                    })
print(df2)

В основном Мне нужно преобразовать df в df2. Примечание: для вопроса и топики существует общий разделитель "_". c для каждой метки столбца.

Как всегда, большое спасибо за помощь в продвинутом. Без этого сообщества я бы иногда серьезно застревал, и благодаря этой платформе я многому учусь.

Ответы [ 2 ]

3 голосов
/ 05 апреля 2020

Использование:

#convert to MultiIndex all not Q topic columns
df2 = df.set_index(['Survey ID','Gender'])
#split columns names to MultiIndex in columns
df2.columns = df2.columns.str.split(expand=True)
#reshape
df2 = df2.stack()
#filter only rows with at least one 1 per row and reshape for remove NaNs
#also replace 0 to NaNs
df2 = df2[df2.eq(1).any(axis=1)].replace(0, np.nan).stack().reset_index(level=2)

#added helper level to MultiIndex because possible duplicates by counter
df2['g'] = df2.groupby(level=[0,1,2]).cumcount()
#final reshape
df2 = (df2.set_index('g', append=True)['level_2']
          .unstack(2)
          .reset_index(level=2, drop=True)
          .reset_index())

print (df2)
   Survey ID  Gender Q1_Topic Q2_Topic
0          1    Male        B      NaN
1          1    Male        C      NaN
2          2  Female        A        Y
3          3    Male        A        X
4          3    Male        B        Z
0 голосов
/ 05 апреля 2020

Как насчет этого кода? Это не причудливый код, а интуитивно понятный.

import pandas as pd
import numpy as np

df1 = pd.DataFrame({'Survey ID': [1,2,3],
                   'Q1_Topic A': [0,1,1], 
                   'Q1_Topic B': [1,0,1], 
                   'Q1_Topic C': [1,0,0],
                   'Q2_Topic A': [0,0,1], 
                   'Q2_Topic B': [0,1,0], 
                   'Q2_Topic C': [0,0,1],
                   'Gender': ['Male', 'Female', 'Male']
                  })

values = []

for ind, row in df1.iterrows():
    survey_ID = row['Survey ID']
    Gender = row['Gender']
    Q1 = row['Q1_Topic A'] * ['A'] + row['Q1_Topic B'] * ['B'] + row['Q1_Topic C'] * ['C']
    Q2 = row['Q2_Topic A'] * ['A'] + row['Q2_Topic B'] * ['B'] + row['Q2_Topic C'] * ['C']

    for i in range(max(len(Q1), len(Q2))):
        if i >= len(Q1):
            record = [survey_ID, np.nan, Q2[i], Gender]
        elif i >= len(Q2):
            record = [survey_ID, Q1[i], np.nan, Gender]
        else:
            record = [survey_ID, Q1[i], Q2[i], Gender]
        values.append(record)

df2 = pd.DataFrame(values, columns = ['Survey ID', 'Q1', 'Q2', 'Gender'])
...