问题描述
我正在尝试使用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,2: 25.0,'Unnamed: 12': {0: 26.0,3: 26.0,'Unnamed: 13': {0: 27.0,'Unnamed: 14': {0: 28.0,4: 28.0},'Unnamed: 15': {0: 29.0,'Unnamed: 16': {0: 30.0,...}
解决方法
第一步,
让我们删除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+',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
,
此解决方案有点难看,但是应该可以。本质上,您是数据框的子集,以挑选出与特定问题关联的所有列。其次,您使用函数来选择每一行中不是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。