我可以更有效地拆分包含元组/无的混合列吗?

ang*_*s l 7 python dataframe pandas

我有一个简单的DataFrame:

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)
Run Code Online (Sandbox Code Playgroud)

然后,我可以非常简单地将元组列分为两部分,例如

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
Run Code Online (Sandbox Code Playgroud)

这种方法也适用:

df[['x','y']] = df.apply(lambda x:x.tuples,result_type='expand',axis=1)
Run Code Online (Sandbox Code Playgroud)

但是,如果我的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)
Run Code Online (Sandbox Code Playgroud)

然后第一种方法会抛出“列的长度必须与键的长度相同”(当然),因为有些行有两个值,有些行没有,并且我的代码预期有两个。

我可以使用.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
Run Code Online (Sandbox Code Playgroud)

[此外:进行索引的方式很有用,仅从右侧分配相关行,而无需指定它们。

但是,我不能使用.loc一次创建两个列,例如

# This isn't valid use of .loc
df.loc[get_rows,['x','y']] = df.loc[get_rows,'tuples'].map(lambda x:list(x))
Run Code Online (Sandbox Code Playgroud)

因为它会引发错误“形状不匹配:形状(2,2)的值数组无法广播到形状(2,)的索引结果”。

我也不能用这个

df[get_rows][['x','y']] = df[get_rows].apply(lambda x:x.tuples,result_type='expand',axis=1)
Run Code Online (Sandbox Code Playgroud)

因为它会抛出通常的“试图在DataFrame的切片副本上设置一个值。尝试使用.loc ...”

我不禁以为我错过了一些东西。

Yua*_*uan 2

df[get_rows] 是一个副本,将值设置为 df[get_rows][['x','y']]不会更改基础数据。只需使用 df[['x','y']] 创建 now 列。

df = pd.DataFrame({'id':list('abcd')})

df['tuples'] = df.index.map(lambda i:(i,i+1) if i%2 else None)

get_rows = df.tuples.notnull()

df[['x','y']] = df[get_rows].apply(lambda x:x.tuples,result_type='expand',axis=1)

print(df)

  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
Run Code Online (Sandbox Code Playgroud)