【问题标题】:Restructure dataframe (maybe pivot or unpivot) to have each column display the label of data based on 0's and 1's重组数据框(可能是枢轴或反枢轴)以使每列显示基于 0 和 1 的数据标签
【发布时间】:2020-04-05 04:33:09
【问题描述】:

我有调查数据。该调查提出一个问题,受访者为每个问题选择一个或多个给定类别。然后,该调查会询问人口统计问题,例如性别。输出是一个数据框,其中人口统计信息作为列,每个问题中每个类别的 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。 注意:每个列标签的问题和主题都有一个通用的分隔符“_”。

一如既往,非常感谢您在高级方面的帮助。如果没有这个社区,我有时会被严重卡住,但我通过这个平台学到了很多东西。

【问题讨论】:

  • Q2_Topic A 来自哪里?这是什么逻辑?
  • 抱歉,这是打字机。问题 2 现在有 X、Y 和 Z 类别。基本上每个问题都有独特的类别可供选择。如果他们选择了一个类别,则为 1,否则为 0

标签: python pandas dataframe pivot transform


【解决方案1】:

用途:

#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

【讨论】:

  • 嗨@jezrael 我没有在我的真实 DF 上得到正确的数字。我真正的 DF 在link。我使用了相同的代码,除了将拆分调整为在“_”处拆分我一直在花费数小时试图弄清楚数字不相加。我们将一如既往地感谢您的帮助。
  • @Mish - 超级,数据已下载。您还可以获得预期的输出或测试数据的某种方式吗?换句话说,我如何测试输出是否需要?
  • 好的,基本上这是为了可视化而进入画面。 Tableau 不喜欢一堆 0 和 1。每列都是一个主题,并使用“_”@jezrael 将其分组,就像我发布的示例一样,我需要将每个组作为一列输出,并且每列中将包含主题的值或一个空值。这有意义吗?
  • 例如。输出应该有一个名为“Stream 4 Topics”的列,因为它位于“_”之前。当我计算在我的原始 DF 中出现多少次“可访问性”时,我得到 14,因为有 14 个 1。但是输出显示在该列中它出现了 42 次,这是不正确的。
  • @Mish - 是否有可能从第一行获得预期输出?
【解决方案2】:

这段代码怎么样?它不是花哨的代码,而是直观的。

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'])

【讨论】:

  • 这没关系,但真实的东西有很多列。 5 个问题,每个问题都有很多主题,大约有 178 列。输入代码将是一场噩梦。
猜你喜欢
  • 2017-06-10
  • 2017-04-08
  • 2022-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多