我尝试根据条件为数据框架中的新列赋值,无论第一列是否包含某个字母。如果第一列只包含一个字母,我使用哑变量函数。但是,如果第一列包含数字、字符串和Nan呢?
下面是一个例子:
# Before
c1
0 a
1 2
2 b
3 c
4 ab
5 bc
6 NaN
#After
c1 a b c
0 a 1 0 0
1 2 0 0 0
2 b 0 1 0
3 c 0 0 1
4 ab 1 1 0
5 bc 0 1 1
6 NaN 0 0 0
我尝试str.contains()
分配,但我得到一个错误:
x['a'] = 1 if x.c1.str.contains('a') else 0
The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
你可以这样做:
df['a'] = df['c1'].str.contains('a').astype(int)
…但是,如果您在df['c1']
中有任何NaN
值(如您在示例中所做的),则会引发ValueError
。
这里有一个使用df.apply
的替代方案:
df['a'] = df['c1'].apply(lambda x: int('a' in x) if isinstance(x, str) else 0)
此方法还处理由多种类型组成的列:除了包含适当的字符外,只有当给定的行是字符串时,它才返回1。
对于您的问题,您可以使用pandas.get_dummies()函数,该函数将分类变量转换为指示器
- 将您的数据帧转换为列表然后(可选) 然后用以下代码创建分类虚拟变量:
lst = ['a', 2, 'b', 'c', 'ab', np.nan]
pd.get_dummies(lst).T
- 比较和合并您想要的结果的伪标识符
您可以通过多种方式做到这一点您的主要问题之一是您的列不是字符串,您可以这样做:
df = pd.DataFrame([{"c1": "a"}, {"c1":2}])
df["new_column"] = 0
df["new_column"][df["c1"].astype(str).str.contains('a')] = 1
或
def custom_funct(row):
print(row)
if "a" in str(row["c1"]):
row["new_column"] = 1
else:
row["new_column"] = 0
return row
df = pd.DataFrame([{"c1": "a"}, {"c1":2}])
df["new_column"] = None
df = df.apply(custom_funct,axis=1)
df
c1
0 a
1 2
2 b
3 c
4 ab
5 bc
6 NaN
首先,您可以用一些虚拟字符(例如#)替换NaN
s,因为它将更容易处理字符串。然后您可以将apply
list
转换为整个列,这样您就可以分别获得每个字符。此后,您可以使用explode
将每行中的每个字符分隔成多行。转换为数据框架并添加一列,以便创建数据透视表。
temp = df['c1'].fillna('#').apply(list).explode().to_frame().reset_index()
temp['vals'] = 1
temp
index c1 vals
0 0 a 1
1 1 2 1
2 2 b 1
3 3 c 1
4 4 a 1
5 4 b 1
6 5 b 1
7 5 c 1
8 6 # 1
然后可以创建pivot_table
,其中c1
为列,列的值为1。在那之后,你可以只保留用字母表示的列。最后,将temp
表与原来的df连接起来。
temp = pd.pivot_table(temp, columns='c1', index="index", values='vals')
cols_retain = [c for c in temp.columns if re.search(r'[A-Za-z]', c)]
pd.concat([df, temp[cols_retain].fillna(0)], axis=1)
c1 a b c
0 a 1.0 0.0 0.0
1 2 0.0 0.0 0.0
2 b 0.0 1.0 0.0
3 c 0.0 0.0 1.0
4 ab 1.0 1.0 0.0
5 bc 0.0 1.0 1.0
6 NaN 0.0 0.0 0.0