我有2个数据帧,我想从一个列中获取一个列,并根据多个(其他)列中的值在第二个列中创建一个新列
第一个dataframe(df1
):
df1 = pd.DataFrame({'cond': np.repeat([1,2], 5),
'point': np.tile(np.arange(1,6), 2),
'value1': np.random.rand(10),
'unused1': np.random.rand(10)})
cond point unused1 value1
0 1 1 0.923699 0.103046
1 1 2 0.046528 0.188408
2 1 3 0.677052 0.481349
3 1 4 0.464000 0.807454
4 1 5 0.180575 0.962032
5 2 1 0.941624 0.437961
6 2 2 0.489738 0.026166
7 2 3 0.739453 0.109630
8 2 4 0.338997 0.415101
9 2 5 0.310235 0.660748
和第二个(df2
):
df2 = pd.DataFrame({'cond': np.repeat([1,2], 10),
'point': np.tile(np.arange(1,6), 4),
'value2': np.random.rand(20)})
cond point value2
0 1 1 0.990252
1 1 2 0.534813
2 1 3 0.407325
3 1 4 0.969288
4 1 5 0.085832
5 1 1 0.922026
6 1 2 0.567615
7 1 3 0.174402
8 1 4 0.469556
9 1 5 0.511182
10 2 1 0.219902
11 2 2 0.761498
12 2 3 0.406981
13 2 4 0.551322
14 2 5 0.727761
15 2 1 0.075048
16 2 2 0.159903
17 2 3 0.726013
18 2 4 0.848213
19 2 5 0.284404
df1['value1']
包含的每个组合的值cond
和point
.
我想创建一个包含值的新列(new_column
),但值应该是2个数据帧中匹配和匹配的值.df2
df1['value1']
cond
point
所以我想要的输出看起来像这样:
cond point value2 new_column
0 1 1 0.990252 0.103046
1 1 2 0.534813 0.188408
2 1 3 0.407325 0.481349
3 1 4 0.969288 0.807454
4 1 5 0.085832 0.962032
5 1 1 0.922026 0.103046
6 1 2 0.567615 0.188408
7 1 3 0.174402 0.481349
8 1 4 0.469556 0.807454
9 1 5 0.511182 0.962032
10 2 1 0.219902 0.437961
11 2 2 0.761498 0.026166
12 2 3 0.406981 0.109630
13 2 4 0.551322 0.415101
14 2 5 0.727761 0.660748
15 2 1 0.075048 0.437961
16 2 2 0.159903 0.026166
17 2 3 0.726013 0.109630
18 2 4 0.848213 0.415101
19 2 5 0.284404 0.660748
在这个例子中,我可以使用tile/repeat,但实际上df1['value1']
并不适合其他数据帧.所以我只需要根据匹配cond
和point
列来完成它
我尝试合并它们,但1)数字似乎不匹配2)我不想带来任何未使用的列df1
:
df1.merge(df2, left_on=['cond', 'point'], right_on=['cond', 'point'])
什么是添加这个新列的正确方法,而不必迭代2个数据帧?
1> piRSquared..:
选项1
对于pure的宽限度和速度pandas
,我们可以使用lookup
This将产生与所有其他选项相同的输出,如下所示。
概念是将查询数据表示为二维数组,并使用索引表示查询值。
d1 = df1.set_index(['cond', 'point']).value1.unstack()
df2.assign(new_column=d1.lookup(df2.cond, df2.point))
选项2如果以相同的方式显示值,
我们可以做同样的事情numpy
来提高性能df1
。这非常快!
a = df1.value1.values.reshape(2, -1)
df2.assign(new_column=a[df2.cond.values - 1, df2.point.values - 1])
选项3
规范的答案是merge
与left
参数一起使用,
但是我们需要做一些准备df1
才能确定输出
d1 = df1[['cond', 'point', 'value1']].rename(columns={'value1': 'new_column'})
df2.merge(d1, 'left')
选项4
我认为这很有趣。构建一个映射字典和一系列映射以
针对小型数据而不是大型数据进行映射。请参见下面的时序。
c1 = df1.cond.values.tolist()
p1 = df1.point.values.tolist()
v1 = df1.value1.values.tolist()
m = {(c, p): v for c, p, v in zip(c1, p1, v1)}
c2 = df2.cond.values.tolist()
p2 = df2.point.values.tolist()
i2 = df2.index.values.tolist()
s2 = pd.Series({i: (c, p) for i, c, p in zip(i2, c2, p2)})
df2.assign(new_column=s2.map(m))
输出值
cond point value2 new_column
0 1 1 0.990252 0.103046
1 1 2 0.534813 0.188408
2 1 3 0.407325 0.481349
3 1 4 0.969288 0.807454
4 1 5 0.085832 0.962032
5 1 1 0.922026 0.103046
6 1 2 0.567615 0.188408
7 1 3 0.174402 0.481349
8 1 4 0.469556 0.807454
9 1 5 0.511182 0.962032
10 2 1 0.219902 0.437961
11 2 2 0.761498 0.026166
12 2 3 0.406981 0.109630
13 2 4 0.551322 0.415101
14 2 5 0.727761 0.660748
15 2 1 0.075048 0.437961
16 2 2 0.159903 0.026166
17 2 3 0.726013 0.109630
18 2 4 0.848213 0.415101
19 2 5 0.284404 0.660748
定时
小数据
%%timeit
a = df1.value1.values.reshape(2, -1)
df2.assign(new_column=a[df2.cond.values - 1, df2.point.values - 1])
1000 loops, best of 3: 304 µs per loop
%%timeit
d1 = df1.set_index(['cond', 'point']).value1.unstack()
df2.assign(new_column=d1.lookup(df2.cond, df2.point))
100 loops, best of 3: 1.8 ms per loop
%%timeit
c1 = df1.cond.values.tolist()
p1 = df1.point.values.tolist()
v1 = df1.value1.values.tolist()
m = {(c, p): v for c, p, v in zip(c1, p1, v1)}
?
c2 = df2.cond.values.tolist()
p2 = df2.point.values.tolist()
i2 = df2.index.values.tolist()
s2 = pd.Series({i: (c, p) for i, c, p in zip(i2, c2, p2)})
?
df2.assign(new_column=s2.map(m))
1000 loops, best of 3: 719 µs per loop
%%timeit
d1 = df1[['cond', 'point', 'value1']].rename(columns={'value1': 'new_column'})
df2.merge(d1, 'left')
100 loops, best of 3: 2.04 ms per loop
%%timeit
df = pd.merge(df2, df1.drop('unused1', axis=1), 'left')
df.rename(columns={'value1': 'new_column'})
100 loops, best of 3: 2.01 ms per loop
%%timeit
df = df2.join(df1.drop('unused1', axis=1).set_index(['cond', 'point']), on=['cond', 'point'])
df.rename(columns={'value1': 'new_column'})
100 loops, best of 3: 2.15 ms per loop
大数据
df2 = pd.concat([df2] * 10000, ignore_index=True)
%%timeit
a = df1.value1.values.reshape(2, -1)
df2.assign(new_column=a[df2.cond.values - 1, df2.point.values - 1])
1000 loops, best of 3: 1.93 ms per loop
%%timeit
d1 = df1.set_index(['cond', 'point']).value1.unstack()
df2.assign(new_column=d1.lookup(df2.cond, df2.point))
100 loops, best of 3: 5.58 ms per loop
%%timeit
c1 = df1.cond.values.tolist()
p1 = df1.point.values.tolist()
v1 = df1.value1.values.tolist()
m = {(c, p): v for c, p, v in zip(c1, p1, v1)}
?
c2 = df2.cond.values.tolist()
p2 = df2.point.values.tolist()
i2 = df2.index.values.tolist()
s2 = pd.Series({i: (c, p) for i, c, p in zip(i2, c2, p2)})
?
df2.assign(new_column=s2.map(m))
10 loops, best of 3: 135 ms per loop
%%timeit
d1 = df1[['cond', 'point', 'value1']].rename(columns={'value1': 'new_column'})
df2.merge(d1, 'left')
100 loops, best of 3: 13.4 ms per loop
%%timeit
df = pd.merge(df2, df1.drop('unused1', axis=1), 'left')
df.rename(columns={'value1': 'new_column'})
10 loops, best of 3: 19.8 ms per loop
%%timeit
df = df2.join(df1.drop('unused1', axis=1).set_index(['cond', 'point']), on=['cond', 'point'])
df.rename(columns={'value1': 'new_column'})
100 loops, best of 3: 18.2 ms per loop