我想添加新行并在现有列的基础上添加新列。例如,假设我有以下数据框:
A B
1 a
2 b
3 c
4 b
还有一个具有唯一B列值作为键的字典。每个键都与值列表关联。这些值用于新的行和列:
{a: [x, y, z], b: [x, w, r], c: [x, q]}
转换将导致以下数据框:
A C
1 x
1 y
1 z
2 x
2 w
2 r
3 x
3 q
4 x
4 w
4 r
我知道如何添加新列,但是我一直试图复制行。最有效的解决方案是什么?我要更新现有的数据框还是创建一个新的数据框?
更新
该操作将在使用Dask的大型数据帧(超过2000万行)上使用。
答案 0 :(得分:2)
我建议使用map
,np.repeat
和chain.from_iterable
创建新内容:
d = {'a': ['x', 'y', 'z'], 'b': ['x', 'w', 'r'], 'c': ['x', 'q']}
s = df['B'].map(d)
lens = [len(x) for x in s]
from itertools import chain
df = pd.DataFrame({
'A' : df['A'].values.repeat(lens),
'C' : list(chain.from_iterable(s.values.tolist()))
})
print (df)
A C
0 1 x
1 1 y
2 1 z
3 2 x
4 2 w
5 2 r
6 3 x
7 3 q
8 4 x
9 4 w
10 4 r
如果字典的某些值不匹配,则可以使用更通用的解决方案:
第一个解决方案返回错误,因为map
返回缺少的值:
TypeError:类型为'NoneType'的对象没有len()
print (df)
A B
0 1 d <- change data
1 2 b
2 3 c
3 4 b
d = {'a': ['x', 'y', 'z'], 'b': ['x', 'w', 'r'], 'c': ['x', 'q']}
s = [d.get(x, [x]) for x in df['B']]
print (s)
[['d'], ['x', 'w', 'r'], ['x', 'q'], ['x', 'w', 'r']]
lens = [len(x) for x in s]
from itertools import chain
df = pd.DataFrame({
'A' : df['A'].values.repeat(lens),
'B' : list(chain.from_iterable(s))
})
print (df)
A B
0 1 d
1 2 x
2 2 w
3 2 r
4 3 x
5 3 q
6 4 x
7 4 w
8 4 r
由于使用dask
,因此另一个解决方案应该是:
d = {'a': ['x', 'y', 'z'], 'b': ['x', 'w', 'r'], 'c': ['x', 'q']}
df1 = pd.DataFrame([(k, y) for k, v in d.items() for y in v], columns=['B','C'])
print (df1)
B C
0 a x
1 a y
2 a z
3 b x
4 b w
5 b r
6 c x
7 c q
df = df.merge(df1, on='B', how='left')
print (df)
A B C
0 1 a x
1 1 a y
2 1 a z
3 2 b x
4 2 b w
5 2 b r
6 3 c x
7 3 c q
8 4 b x
9 4 b w
10 4 b r
答案 1 :(得分:2)
您可以将dict转换为包含名为B
和C
的列的DataFrame
df2 = pd.DataFrame.from_dict(d, orient='index').stack().reset_index().iloc[:, [0, -1]]
df2.columns = ['B', 'C']
将此新的df2
与您的初始df
合并,然后选择您想要的数据:
df.merge(df2, on='B').set_index('A')['C'].sort_index()
答案 2 :(得分:2)
使用sum()
和map()
的另一种方法:
d = {'a': ['x', 'y', 'z'], 'b': ['x', 'w', 'r'], 'c': ['x', 'q']}
df_new= pd.DataFrame({'A': np.repeat(df.A,df.B.map(d).apply(len)).\
reset_index(drop=True),'B':df.B.map(d).sum()})
或者使用运算符reduce更好(对于大型数据框):
import functools,operator
df_new= pd.DataFrame({'A': np.repeat(df.A,df.B.map(d).apply(len)).\
reset_index(drop=True),'B':functools.reduce(operator.iadd, df.B.map(d),[])})
print(df_new)
A B
0 1 x
1 1 y
2 1 z
3 2 x
4 2 w
5 2 r
6 3 x
7 3 q
8 4 x
9 4 w
10 4 r
答案 3 :(得分:1)
我的答案-创建新的DF。
di = {'a': ['x', 'y', 'z'], 'b': ['x', 'w', 'r'], 'c': ['x', 'q']}
x = df.to_dict()
temp = list(zip(df.A, [di[z] for z in x['B'].values()]))
A = [[x[0]] * len(x[1]) for x in temp]
B = [x[1] for x in temp]
A = [item for sublist in A for item in sublist]
B = [item for sublist in B for item in sublist]
pd.DataFrame({'A':A, 'B':B})