我有一个简单的数据框:
import pandas as pd
df = pd.DataFrame({'id':list('abcd')})
df['tuples'] = df.index.map(lambda i:(i,i+1))
# outputs:
# id tuples
# 0 a (0, 1)
# 1 b (1, 2)
# 2 c (2, 3)
# 3 d (3, 4)
我可以将元组列非常简单地拆分成两个,例如:
df[['x','y']] = pd.DataFrame(df.tuples.tolist())
# outputs:
# id tuples x y
# 0 a (0, 1) 0 1
# 1 b (1, 2) 1 2
# 2 c (2, 3) 2 3
# 3 d (3, 4) 3 4
这种方法也可以起作用:
df[['x','y']] = df.apply(lambda x:x.tuples,result_type='expand',axis=1)
不过,如果我的DataFrame稍微复杂一些,例如:
df = pd.DataFrame({'id':list('abcd')})
df['tuples'] = df.index.map(lambda i:(i,i+1) if i%2 else None)
# outputs:
# id tuples
# 0 a None
# 1 b (1, 2)
# 2 c None
# 3 d (3, 4)
第一种方法会抛出“列必须与关键字长度相同”的错误(当然),因为某些行有两个值,而有些行没有值,而我的代码预计有两个值。
我可以使用.loc两次创建单个列。
get_rows = df.tuples.notnull() # return rows with tuples
df.loc[get_rows,'x'] = df.tuples.str[0]
df.loc[get_rows,'y'] = df.tuples.str[1]
# outputs:
# id tuples x y
# 0 a None NaN NaN
# 1 b (1, 2) 1.0 2.0
# 2 c None NaN NaN
# 3 d (3, 4) 3.0 4.0
[旁注: 索引功能很有用,它可以仅选择右边相关的行而无需指定它们。]
然而,我不能使用.loc一次创建两个列,例如:
# This isn't valid use of .loc
df.loc[get_rows,['x','y']] = df.loc[get_rows,'tuples'].map(lambda x:list(x))
由于形状不匹配,它会抛出错误“形状不匹配:形状为(2,2)的值数组无法广播到形状为(2,)的索引结果”。
我也不能使用这个。
df[get_rows][['x','y']] = df[get_rows].apply(lambda x:x.tuples,result_type='expand',axis=1)
由于数据框切片的复制问题,通常会出现“A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc…” 错误信息。
我无法不去想我是否漏掉了什么。
df[get_rows][['x','y']]
更改为df.loc[get_rows, ['x','y']]
。 - Yuca