Python 连接数据帧中的列值,同时忽略NAN

Python 连接数据帧中的列值,同时忽略NAN,python,string,pandas,dataframe,nan,Python,String,Pandas,Dataframe,Nan,我有一张桌子在下面 df: 现在,我正在尝试连接除第一列之外的所有列,我希望我的数据框按以下方式显示 新的"基本法": EVNT_ID col1 col2 col3 col4 new_col 123454 1 Nan 4 5 1|4|5 628392 Nan 3 Nan 7 3|7 293899 2 Nan Nan 6 2|6 127820 9 11 12 19 9|11|12|19 我正在使用

我有一张桌子在下面

df:

现在,我正在尝试连接除第一列之外的所有列,我希望我的数据框按以下方式显示

新的"基本法":

 EVNT_ID col1 col2 col3 col4 new_col
 123454   1    Nan   4    5   1|4|5
 628392   Nan   3   Nan   7    3|7
 293899   2    Nan  Nan   6    2|6
 127820   9    11    12   19  9|11|12|19
我正在使用以下代码

df['new_column'] = df[~df.EVNT_ID].apply(lambda x: '|'.join(x.dropna().astype(str).values), axis=1)
但它给了我以下的错误

输入类型不支持ufunc“invert”,并且无法根据强制转换规则安全地将输入强制为任何受支持的类型

如果有人能告诉我哪里错了,我将不胜感激。我非常感谢。

您可以使用过滤器和agg:

或者

如果性能很重要,您可以使用列表:

joined = [
    '|'.join([str(int(x)) for x in r if pd.notna(x)]) 
    for r in df.iloc[:,1:].values.tolist()
]
joined
# ['1|4|5', '3|7', '2|6', '9|11|12|19']

df.assign(new_col=joined)   

   EVNT_ID  col1  col2  col3  col4     new_col
0   123454   1.0   NaN   4.0     5       1|4|5
1   628392   NaN   3.0   NaN     7         3|7
2   293899   2.0   NaN   NaN     6         2|6
3   127820   9.0  11.0  12.0    19  9|11|12|19
如果您可以原谅数据帧分配的开销,下面是两个最快解决方案的计时

df = pd.concat([df] * 1000, ignore_index=True)

# In this post.
%%timeit
[
     '|'.join([str(int(x)) for x in r if pd.notna(x)]) 
     for r in df.iloc[:,1:].values.tolist()
]
# RafaelC's answer.
%%timeit
[
    '|'.join([k for k in a if k])
    for a in zip(*df.fillna('').astype(str).iloc[:, 1:].values.tolist())
]    

31.9 ms ± 800 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
23.7 ms ± 409 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
尽管注意到答案并不完全相同,因为@RafaelC的代码生成浮点数:['1.0 | 2.0 | 9.0','3.0 | 11.0',…]。如果这很好,那就太好了。否则,您将需要转换为int,这将增加更多开销。

您可以使用filter和agg执行此操作:

或者

如果性能很重要,您可以使用列表:

joined = [
    '|'.join([str(int(x)) for x in r if pd.notna(x)]) 
    for r in df.iloc[:,1:].values.tolist()
]
joined
# ['1|4|5', '3|7', '2|6', '9|11|12|19']

df.assign(new_col=joined)   

   EVNT_ID  col1  col2  col3  col4     new_col
0   123454   1.0   NaN   4.0     5       1|4|5
1   628392   NaN   3.0   NaN     7         3|7
2   293899   2.0   NaN   NaN     6         2|6
3   127820   9.0  11.0  12.0    19  9|11|12|19
如果您可以原谅数据帧分配的开销,下面是两个最快解决方案的计时

df = pd.concat([df] * 1000, ignore_index=True)

# In this post.
%%timeit
[
     '|'.join([str(int(x)) for x in r if pd.notna(x)]) 
     for r in df.iloc[:,1:].values.tolist()
]
# RafaelC's answer.
%%timeit
[
    '|'.join([k for k in a if k])
    for a in zip(*df.fillna('').astype(str).iloc[:, 1:].values.tolist())
]    

31.9 ms ± 800 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
23.7 ms ± 409 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

尽管注意到答案并不完全相同,因为@RafaelC的代码生成浮点数:['1.0 | 2.0 | 9.0','3.0 | 11.0',…]。如果这很好,那就太好了。否则,您将需要转换为int,这会增加更多开销。

使用列表理解和zip

时机似乎还可以

df = pd.concat([df]*1000)

%timeit [['|'.join([k for k in a if k])] for a in zip(*df.fillna('').astype(str).iloc[:, 1:].values)]
10.8 ms ± 568 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit df.filter(like='col').agg(lambda x: x.dropna().astype(int).astype(str).str.cat(sep='|'), axis=1)
1.68 s ± 91.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit df.iloc[:, 1:].apply(lambda x: '|'.join(str(el) for el in x if str(el) != 'nan'), axis=1)
87.8 ms ± 5.01 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit df.assign(new_col=['|'.join([str(int(x)) for x in r if ~np.isnan(x)]) for r in df.iloc[:,1:].values])
45.1 ms ± 1.38 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

使用列表理解和zip

时机似乎还可以

df = pd.concat([df]*1000)

%timeit [['|'.join([k for k in a if k])] for a in zip(*df.fillna('').astype(str).iloc[:, 1:].values)]
10.8 ms ± 568 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit df.filter(like='col').agg(lambda x: x.dropna().astype(int).astype(str).str.cat(sep='|'), axis=1)
1.68 s ± 91.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit df.iloc[:, 1:].apply(lambda x: '|'.join(str(el) for el in x if str(el) != 'nan'), axis=1)
87.8 ms ± 5.01 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit df.assign(new_col=['|'.join([str(int(x)) for x in r if ~np.isnan(x)]) for r in df.iloc[:,1:].values])
45.1 ms ± 1.38 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

请尝试以下代码:

df['new_col'] = df.iloc[:, 1:].apply(lambda x:
    '|'.join(str(el) for el in x if str(el) != 'nan'), axis=1)
起初,我想到的是x.dropna而不是x if strel!='南,,
但是%的时间表明dropna的工作速度要慢得多。

请尝试以下代码:

df['new_col'] = df.iloc[:, 1:].apply(lambda x:
    '|'.join(str(el) for el in x if str(el) != 'nan'), axis=1)
起初,我想到的是x.dropna而不是x if strel!='南,,
但是%的时间表明dropna的工作速度要慢得多。

感谢您的计时!虽然这不是一个特别公平的比较,除非第一个列表comp也被分配,因为这会产生开销;这足以让事情有所不同!我的回答也反映了你的时间安排。我看到了。感谢您的投入!:}我们的答案也不完全相同。您的代码生成浮点:['1.0 | 2.0 | 9.0'、'3.0 | 11.0'、'4.0 | 12.0'、'5 | 7 | 6 | 19']感谢您的计时!虽然这不是一个特别公平的比较,除非第一个列表comp也被分配,因为这会产生开销;这足以让事情有所不同!我的回答也反映了你的时间安排。我看到了。感谢您的投入!:}我们的答案也不完全相同。您的代码生成浮点数:['1.0 | 2.0 | 9.0','3.0 | 11.0','4.0 | 12.0','5 | 7 | 6 | 19']