使用 Pandas 的 SurveyMonkey 数据格式化
Posted
技术标签:
【中文标题】使用 Pandas 的 SurveyMonkey 数据格式化【英文标题】:SurveyMonkey data formatting using Pandas 【发布时间】:2018-09-09 21:01:51 【问题描述】:我有一个调查要分析,该调查由 SurveyMonkey 的参与者完成。不幸的是,数据的组织方式并不理想,因为每个问题的每个分类响应都有自己的列。
例如,这里是数据框中的一个响应的前几行:
How long have you been participating in the Garden Awards Program? \
0 One year
1 NaN
2 NaN
3 NaN
4 NaN
Unnamed: 10 Unnamed: 11 Unnamed: 12 \
0 2-3 years 4-5 years 5 or more years
1 NaN NaN NaN
2 NaN 4-5 years NaN
3 2-3 years NaN NaN
4 NaN NaN 5 or more years
How did you initially learn of the Garden Awards Program? \
0 I nominated my garden to be evaluated
1 NaN
2 I nominated my garden to be evaluated
3 NaN
4 NaN
Unnamed: 14 etc...
0 A friend or family member nominated my garden ...
1 A friend or family member nominated my garden ...
2 NaN
3 NaN
4 NaN
这个问题,How long have you been participating in the Garden Awards Program?
,有有效的回答:one year
、2-3 years
等,并且都在第一行作为哪个列保存哪个值的键。这是第一个问题。 (How did you initially learn of the Garden Awards Program?
也是如此,其中有效的响应是:I nominated my garden to be evaluated
、A friend or family member nominated my garden
等)。
第二个问题是每个分类响应的附加列都是Unnamed: N
,其中 N 是与所有问题相关联的类别一样多的列。
在我开始将每个问题的列重新映射和展平/折叠成一个列之前,我想知道是否有任何其他方法可以使用 Pandas 处理像这样呈现的调查数据。我的所有搜索都指向了 SurveyMonkey API,但我看不出它有什么用处。
我猜我需要展平列,因此,如果有人能提出一种方法,那就太好了。我在想有一种方法可以通过抓取相邻的列来继续抓取属于分类响应的所有列,直到 Unnamed
不再在列名中,但我不知道如何做到这一点。
【问题讨论】:
您能否将 DataFrame 的前几行作为文本而不是图像发布? 按要求完成。一个主要问题是,有很多这些分组的分类响应列,每个列跨越每个问题的几个列,因此重新映射这些将是一个皇家 PITA。 【参考方案1】:我将使用以下DataFrame
(可以从here下载为CSV):
Q1 Unnamed: 2 Unnamed: 3 Q2 Unnamed: 5 Unnamed: 6 Q3 Unnamed: 7 Unnamed: 8
0 A1-A A1-B A1-C A2-A A2-B A2-C A3-A A4-B A3-C
1 A1-A NaN NaN NaN A2-B NaN NaN NaN A3-C
2 NaN A1-B NaN A2-A NaN NaN NaN A4-B NaN
3 NaN NaN A1-C NaN A2-B NaN A3-A NaN NaN
4 NaN A1-B NaN NaN NaN A2-C NaN NaN A3-C
5 A1-A NaN NaN NaN A2-B NaN A3-A NaN NaN
关键假设:
-
名称不以
Unnamed
开头的每一列实际上都是问题的标题
问题标题之间的列代表列间隔左端问题的选项
解决方案概述:
-
查找每个问题开始和结束位置的索引
将每个问题扁平化为一列 (
pd.Series
)
将问题列重新合并在一起
实施(第 1 部分):
indices = [i for i, c in enumerate(df.columns) if not c.startswith('Unnamed')]
questions = [c for c in df.columns if not c.startswith('Unnamed')]
slices = [slice(i, j) for i, j in zip(indices, indices[1:] + [None])]
您可以看到,像下面这样对切片进行迭代,您会得到一个与每个问题相对应的 DataFrame
:
for q in slices:
print(df.iloc[:, q]) # Use `display` if using Jupyter
实施(第 2-3 部分):
def parse_response(s):
try:
return s[~s.isnull()][0]
except IndexError:
return np.nan
data = [df.iloc[:, q].apply(parse_response, axis=1)[1:] for q in slices]
df = pd.concat(data, axis=1)
df.columns = questions
输出:
Q1 Q2 Q3
1 A1-A A2-B A3-C
2 A1-B A2-A A4-B
3 A1-C A2-B A3-A
4 A1-B A2-C A3-C
5 A1-A A2-B A3-A
【讨论】:
不错!我是按照这些思路思考的,但这是完美的! 唯一的问题是假设 3 不一定成立。我在我的数据集上的implementation (part 2-3)
的第一步中收到('index out of bounds', 'occurred at index 1')
的错误,并且可以在您的数据集上重现,当连续响应的所有值都是 NaN、IOW 时,没有非空响应针对特定调查中的特定调查项目。
我将尝试在执行列表理解的步骤中使用np.where
子句,这样如果所有项目都是null
,那么我会将值设置为no response
否则它将是~s.isnull()][0]
或类似的东西......
@horcle_buzz:你可以创建一个更通用的函数,而不是使用np.where
。我编辑了帖子,用常规命名函数 parse_response
替换了 lambda 函数,该函数涵盖了没有有效响应可用的情况。
Gustavo Bezzerra,谢谢。我确实提出了一个完全不同的解决方案,稍后我将发布(不使用np.where
)。以上是关于使用 Pandas 的 SurveyMonkey 数据格式化的主要内容,如果未能解决你的问题,请参考以下文章
SurveyMonkey API v3 创建消息,返回错误:“用户没有发出此请求所需的计划”