我有一种情况,我想通过将另一个较小的表合并到数据框的每一行中来扩展数据框。
换句话说,如果较大的表为10行,而较小的表为2行,则结果将是长度为20的表,其中原始表中的每一行均被复制,而较小表中的新列被合并。
为此,我编写了一个小函数,在每个表上添加一个公共列,在该列上合并,然后删除该列。
def merge_expand(big, small):
placeholder = "__placeholderstring__"
big.insert(0, placeholder, 1)
small.insert(0, placeholder, 1)
merged = big.merge(small, how='left', on=placeholder)
merged.drop(columns=placeholder, inplace=True)
return merged
# example
big = pd.DataFrame({'a': [1,2,3], 'b': [4,5,6]})
small = pd.DataFrame({'id': ['aa','bb'], 'val':['a','b']})
merge_expand(big, small)
# output:
a b id val
0 1 4 aa a
1 1 4 bb b
2 2 5 aa a
3 2 5 bb b
4 3 6 aa a
5 3 6 bb b
这可以完成工作,但是在我看来,它很hacky,可能不是最有效的解决方案,因为它需要执行多个DataFrame操作。解决这个问题的最有效方法是什么?
答案 0 :(得分:1)
您似乎正在寻找完全联接/笛卡尔联接。如果我们为所有观测值分配相同的<template>
<div v-if="project">
<h1>{{ project.name }}</h1>
<router-link :to="/project/someid/views">Views</router-link>
<router-link :to="/project/someid/exports">Exports</router-link>
<router-link :to="/project/someid/recommendations">Recommendations</router-link>
<ul v-if="page==='views">
<li v-for="(view, i) in project.views" :key="i">{{ views }}</div>
</ul>
<ul v-else-if="page==='exports">
<li v-for="(export, i) in project.exports" :key="i">{{ export }}</div>
</ul>
<ul v-else-if="page==='recommendations">
<li v-for="(recommendation, i) in project.recommendations" :key="i">{{ recommendation }}</div>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
project: null
}
},
computed: {
page() {
return this.$route.meta.page;
}
},
mounted() {
this.getProject()
},
methods: {
getProject() {
axios
.get(`/projects/someid`)
.then(res => this.project = res.data)
}
}
}
</script>
,则可以使用pd.merge
完成。
key
输出
big.assign(key=1).merge(small.assign(key=1), how='outer', on='key')
如果您已经有一个名为“键”的列,则基本上可以将其称为:
a b key id val
0 1 4 1 aa a
1 1 4 1 bb b
2 2 5 1 aa a
3 2 5 1 bb b
4 3 6 1 aa a
5 3 6 1 bb b
输出
big['thiswontmatchanything'] = 1
small['thiswontmatchanything'] = 1
big.merge(small, how='outer', on='thiswontmatchanything').drop('thiswontmatchanything', axis=1)
答案 1 :(得分:1)
以下情况可能会减少黑客行为:
每个数据框按照其他原始数据框的长度复制行 第一个按“ a”列排序,但是您可以进行调整 然后将两个数据帧沿列轴(1)串联在一起,以获得所需的结果。
def merge_expand(*args):
tmp_big = pd.concat([args[0]] * len(small), ignore_index=True).sort_values(by=['a']).reset_index(drop=True)
tmp_small = pd.concat([args[1]] * len(big), ignore_index=True)
return pd.concat([tmp_big, tmp_small], 1)
输入:
merge_expand(big, small)
输出:
a b id val
0 1 4 aa a
1 1 4 bb b
2 2 5 aa a
3 2 5 bb b
4 3 6 aa a
5 3 6 bb b
编辑:如果您要传递一些参数,我们甚至可以使其更通用:
def merge_expand(*args):
if len(args) == 2:
if len(args[0]) > len(args[1]):
df_1 = pd.concat([args[0]] * len(args[1]), ignore_index=True).sort_values(by=[args[0].columns[0]]).reset_index(drop=True)
df_2 = pd.concat([args[1]] * len(args[0]), ignore_index=True)
return pd.concat([df_1, df_2], 1)
答案 2 :(得分:1)
我相信有更短的方法。给定数据帧 df1 和 df2,你可以做
df = df1.merge(df2, how='cross')
或
df = df2.merge(df1, how='cross')
您可能会实现一个简单的 if-then-else 来确定哪个数据框较小或较大。但这不包括合并操作。