假设我有
形式的数据Name h1 h2 h3 h4
A 1 nan 2 3
B nan nan 1 3
C 1 3 2 nan
我想将所有非纳米细胞向左移动(或收集新列中的所有非纳米数据),同时保留从左到右的顺序,得到
Name h1 h2 h3 h4
A 1 2 3 nan
B 1 3 nan nan
C 1 3 2 nan
我当然可以一行一行地这样做。但我希望知道是否还有其他方法可以提高性能。
答案 0 :(得分:5)
首先,制作功能。
def squeeze_nan(x):
original_columns = x.index.tolist()
squeezed = x.dropna()
squeezed.index = [original_columns[n] for n in range(squeezed.count())]
return squeezed.reindex(original_columns, fill_value=np.nan)
其次,应用该功能。
df.apply(squeeze_nan, axis=1)
你也可以尝试 axis = 0 和。[:: - 1] 来向任何方向挤压nan。
<强> [编辑] 强>
@ Mxracer888你想要这个吗?
def squeeze_nan(x, hold):
if x.name not in hold:
original_columns = x.index.tolist()
squeezed = x.dropna()
squeezed.index = [original_columns[n] for n in range(squeezed.count())]
return squeezed.reindex(original_columns, fill_value=np.nan)
else:
return x
df.apply(lambda x: squeeze_nan(x, ['B']), axis=1)
答案 1 :(得分:2)
这就是我的所作所为:
我将您的数据帧拆分为更长的格式,然后按名称列进行分组。在每组中,我丢弃NaN,但随后重新索引到完整的h1思想h4集,从而重新创建你的NaN到右边。
from io import StringIO
import pandas
def defragment(x):
values = x.dropna().values
return pandas.Series(values, index=df.columns[:len(values)])
datastring = StringIO("""\
Name h1 h2 h3 h4
A 1 nan 2 3
B nan nan 1 3
C 1 3 2 nan""")
df = pandas.read_table(datastring, sep='\s+').set_index('Name')
long_index = pandas.MultiIndex.from_product([df.index, df.columns])
print(
df.stack()
.groupby(level='Name')
.apply(defragment)
.reindex(long_index)
.unstack()
)
所以我得到了:
h1 h2 h3 h4
A 1 2 3 NaN
B 1 3 NaN NaN
C 1 3 2 NaN
答案 2 :(得分:2)
以下是使用正则表达式(可能不推荐)的方法:
pd.read_csv(StringIO(re.sub(',+',',',df.to_csv())))
Out[20]:
Name h1 h2 h3 h4
0 A 1 2 3 NaN
1 B 1 3 NaN NaN
2 C 1 3 2 NaN
答案 3 :(得分:1)
首先,使用 np.isnan
创建一个布尔数组,这会将 NaN
标记为 True,将非 nan 值标记为 False
,然后对它们进行 argsort,这样您将保持非 - nan 值和 NaN
被推到右边。
idx = np.isnan(df.values).argsort(axis=1)
df = pd.DataFrame(
df.values[np.arange(df.shape[0])[:, None], idx],
index=df.index,
columns=df.columns,
)
h1 h2 h3 h4
Name
A 1.0 2.0 3.0 NaN
B 1.0 3.0 NaN NaN
C 1.0 3.0 2.0 NaN
np.isnan(df.values)
# array([[False, True, False, False],
# [ True, True, False, False],
# [False, False, False, True]])
# False ⟶ 0 True ⟶ 1
# When sorted all True values i.e nan are pushed to the right.
idx = np.isnan(df.values).argsort(axis=1)
# array([[0, 2, 3, 1],
# [2, 3, 0, 1],
# [0, 1, 2, 3]], dtype=int64)
# Now, indexing `df.values` using `idx`
df.values[np.arange(df.shape[0])[:, None], idx]
# array([[ 1., 2., 3., nan],
# [ 1., 3., nan, nan],
# [ 1., 3., 2., nan]])
# Make that as a DataFrame
df = pd.DataFrame(
df.values[np.arange(df.shape[0])[:, None], idx],
index=df.index,
columns=df.columns,
)
# h1 h2 h3 h4
# Name
# A 1.0 2.0 3.0 NaN
# B 1.0 3.0 NaN NaN
# C 1.0 3.0 2.0 NaN