【问题标题】:Read an excel file and merge unnamed columns in Pandas在 Pandas 中读取一个 excel 文件并合并未命名的列
【发布时间】:2020-10-02 16:27:18
【问题描述】:

我正在尝试使用 Pandas 从调查结果表中读取一个 excel 文件(在有参与者的行上),但是我将许多变量分成多个列,就像这样

>>> df.columns
Index([ ... , 'Age', 'Unnamed: 12', 'Unnamed: 13', 'Unnamed: 14', 'Unnamed: 15', 'Unnamed: 16', ...], dtype='object', length=256)

'Age' 之后和下一个命名列之前的每个未命名列仅包含与该多项选择题中的单个选项相对应的 Age 变量的值。 如何获取同一列下的所有年龄值?

编辑:df.head(5).to_dict() 的输出示例:

{...,
'Gender': {0: 'M', 1: 'M', 2: 'M', 3: nan, 4: nan},
 'Unnamed: 10': {0: 'F', 1: nan, 2: nan, 3: 'F', 4: 'F'},
 'Age': {0: 25.0, 1: nan, 2: 25.0, 3: nan, 4: nan},
 'Unnamed: 12': {0: 26.0, 1: nan, 2: nan, 3: 26.0, 4: nan},
 'Unnamed: 13': {0: 27.0, 1: nan, 2: nan, 3: nan, 4: nan},
 'Unnamed: 14': {0: 28.0, 1: nan, 2: nan, 3: nan, 4: 28.0},
 'Unnamed: 15': {0: 29.0, 1: nan, 2: nan, 3: nan, 4: nan},
 'Unnamed: 16': {0: 30.0, 1: nan, 2: nan, 3: nan, 4: nan},
...}

【问题讨论】:

  • 能否提供您正在阅读的 Excel 文件的示例?这将有助于更好地理解问题。
  • 像这样的一行代码吗?如果它不是表格,那么这将是一个问题。如果可能的话,您的 Excel 工作表的屏幕截图会很好。
  • 是的,它是表格的,抱歉……我会截图
  • 这里是:imgur.com/a/2mqsY1I
  • @garpez 查看您拥有的图像,复制并粘贴这些单元格,然后将其粘贴到您的问题中,然后格式化为代码。或执行print(df.head(5).to_dict()) 并将其粘贴到您的问题中并格式化为代码。

标签: python excel pandas survey


【解决方案1】:

第一步,让我们删除Unnamed: 列,然后向前填充值:

df.columns = df.columns.to_series().replace('Unnamed:\s\d+',np.nan,regex=True).ffill().values

print(df)

  Gender Gender   Age   Age   Age   Age   Age   Age
0      M      F  25.0  26.0  27.0  28.0  29.0  30.0
1      M    NaN   NaN   NaN   NaN   NaN   NaN   NaN
2      M    NaN  25.0   NaN   NaN   NaN   NaN   NaN
3    NaN      F   NaN  26.0   NaN   NaN   NaN   NaN
4    NaN      F   NaN   NaN   NaN  28.0   NaN   NaN

然后我们可以重塑您的数据框并创建一个新索引,以便我们可以unstack

s = df.T.agg(list,1).explode().dropna().to_frame()

df1 = s.set_index(s.groupby(level=0).cumcount(),append=True).unstack(0)


print(df1)

  Age Gender
0  25      M
1  25      M
2  26      M
3  26      F
4  27      F
5  28      F
6  28    NaN
7  29    NaN
8  30    NaN

另一种方法是为您的列创建一个多索引,这样会更好,因为您可以保留原始索引:

df.columns = df.columns.to_series()\
               .replace('Unnamed:\s\d+',np.nan,regex=True).ffill().values
df.columns = pd.MultiIndex.from_tuples([(x,y)for x,y in 
                 zip(df.columns,df.columns.to_series().groupby(level=0).cumcount())])


print(df)

  Gender        Age                              
       0    1     0     1     2     3     4     5
0      M    F  25.0  26.0  27.0  28.0  29.0  30.0
1      M  NaN   NaN   NaN   NaN   NaN   NaN   NaN
2      M  NaN  25.0   NaN   NaN   NaN   NaN   NaN
3    NaN    F   NaN  26.0   NaN   NaN   NaN   NaN
4    NaN    F   NaN   NaN   NaN  28.0   NaN   NaN


print(df.stack(1))

      Age Gender
0 0  25.0      M
  1  26.0      F
  2  27.0    NaN
  3  28.0    NaN
  4  29.0    NaN
  5  30.0    NaN
1 0   NaN      M
2 0  25.0      M
3 1  26.0      F
4 1   NaN      F
  3  28.0    NaN

【讨论】:

    【解决方案2】:

    这个解决方案有点难看,但它应该可以工作。本质上,您对数据框进行子集化以挑选出与特定问题相关的所有列。其次,您使用一个函数来挑选出每行中第一个不是 NaN 的值。

    df = df.drop([0])  # Drop first row, contains column headings
    
    # This function treats each row as a Series. It then gets the value
    # of the first defined cell, and returns it. Or, if the row is all
    # None, it returns None.
    def get_first_valid_from_row(x):
        if x.first_valid_index() is None:
            return None
        else:
            return x[x.first_valid_index()]
    
    new_df = pd.DataFrame()
    
    # Get gender-related columns
    gender_subset_df = df[["Gender", "Unnamed: 10"]]
    new_df["Gender"] = gender_subset_df.apply(get_first_valid_from_row, axis=1)
    
    # Get age-related columns
    age_subset_df = df[["Age", "Unnamed: 12", "Unnamed: 13", "Unnamed: 14", "Unnamed: 15", "Unnamed: 16"]]
    new_df["Age"] = age_subset_df.apply(get_first_valid_from_row, axis=1)
    print(new_df)
    

    我得到以下结果:

      Gender   Age
    1      M   NaN
    2      M  25.0
    3      F  26.0
    4      F  28.0
    

    第一行的年龄无效,但查看您的原始数据,您的数据集中的第一个人似乎没有选择任何年龄选项。

    感谢@EdChum 这种方法。

    【讨论】:

    • 谢谢@Nick ODell 和@EdChum!这行得通,虽然有点费时,因为我必须为 20 多个变量(约 300 个未命名的列)执行此操作
    • 如果您重命名列并向前填充,您可以使用print(df.groupby(level=0,axis=1).first()) 获得相同的结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-21
    • 1970-01-01
    • 2014-07-22
    • 2018-05-25
    • 2022-09-23
    • 2022-07-27
    • 2022-07-06
    相关资源
    最近更新 更多