DataFrame#

以下代码仅作为示例,请勿在生产环境直接使用。

推荐使用 jupyter 运行本教程。

隐语提供了联邦数据的DataFrame形式封装。DataFrame由多个参与方的数据块构成,支持数据水平或者垂直切分。

dataframe.png

目前DataFrame兼容了部分pandas接口,使用体感和pandas一致。在计算过程中,原始数据始终保持在数据拥有方本地,不会出域。

下面将展示如何使用DataFrame。

前置准备#

初始化secretflow,创建alice、bob和carol三个参与方。

[1]:
import secretflow as sf

# In case you have a running secretflow runtime already.
sf.shutdown()

sf.init(['alice', 'bob', 'carol'], address='local')
alice, bob, carol = sf.PYU('alice'), sf.PYU('bob'), sf.PYU('carol')

数据准备#

我们使用 iris 作为示例数据集。

[2]:
import pandas as pd
from sklearn.datasets import load_iris

iris = load_iris(as_frame=True)
data = pd.concat([iris.data, iris.target], axis=1)
data
[2]:
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) target
0 5.1 3.5 1.4 0.2 0
1 4.9 3.0 1.4 0.2 0
2 4.7 3.2 1.3 0.2 0
3 4.6 3.1 1.5 0.2 0
4 5.0 3.6 1.4 0.2 0
... ... ... ... ... ...
145 6.7 3.0 5.2 2.3 2
146 6.3 2.5 5.0 1.9 2
147 6.5 3.0 5.2 2.0 2
148 6.2 3.4 5.4 2.3 2
149 5.9 3.0 5.1 1.8 2

150 rows × 5 columns

我们按照水平(特征相同)和垂直(样本相同)两种方式对数据进行切分,以方便后续的演示。

[3]:
# Horizontal partitioning.
h_alice, h_bob, h_carol = data.iloc[:40, :], data.iloc[40:100, :], data.iloc[100:, :]

# Save to temporary files.
import tempfile
import os

temp_dir = tempfile.mkdtemp()

h_alice_path = os.path.join(temp_dir, 'h_alice.csv')
h_bob_path = os.path.join(temp_dir, 'h_bob.csv')
h_carol_path = os.path.join(temp_dir, 'h_carol.csv')
h_alice.to_csv(h_alice_path, index=False)
h_bob.to_csv(h_bob_path, index=False)
h_carol.to_csv(h_carol_path, index=False)
[4]:
h_alice.head(), h_bob.head(), h_carol.head()
[4]:
(   sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)  \
 0                5.1               3.5                1.4               0.2
 1                4.9               3.0                1.4               0.2
 2                4.7               3.2                1.3               0.2
 3                4.6               3.1                1.5               0.2
 4                5.0               3.6                1.4               0.2

    target
 0       0
 1       0
 2       0
 3       0
 4       0  ,
     sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)  \
 40                5.0               3.5                1.3               0.3
 41                4.5               2.3                1.3               0.3
 42                4.4               3.2                1.3               0.2
 43                5.0               3.5                1.6               0.6
 44                5.1               3.8                1.9               0.4

     target
 40       0
 41       0
 42       0
 43       0
 44       0  ,
      sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)  \
 100                6.3               3.3                6.0               2.5
 101                5.8               2.7                5.1               1.9
 102                7.1               3.0                5.9               2.1
 103                6.3               2.9                5.6               1.8
 104                6.5               3.0                5.8               2.2

      target
 100       2
 101       2
 102       2
 103       2
 104       2  )
[5]:
# Vertical partitioning.
v_alice, v_bob, v_carol = data.iloc[:, :2], data.iloc[:, 2:4], data.iloc[:, 4:]

# Save to temporary files.
v_alice_path = os.path.join(temp_dir, 'v_alice.csv')
v_bob_path = os.path.join(temp_dir, 'v_bob.csv')
v_carol_path = os.path.join(temp_dir, 'v_carol.csv')
v_alice.to_csv(v_alice_path, index=False)
v_bob.to_csv(v_bob_path, index=False)
v_carol.to_csv(v_carol_path, index=False)
[6]:
v_alice, v_bob, v_carol
[6]:
(     sepal length (cm)  sepal width (cm)
 0                  5.1               3.5
 1                  4.9               3.0
 2                  4.7               3.2
 3                  4.6               3.1
 4                  5.0               3.6
 ..                 ...               ...
 145                6.7               3.0
 146                6.3               2.5
 147                6.5               3.0
 148                6.2               3.4
 149                5.9               3.0

 [150 rows x 2 columns],
      petal length (cm)  petal width (cm)
 0                  1.4               0.2
 1                  1.4               0.2
 2                  1.3               0.2
 3                  1.5               0.2
 4                  1.4               0.2
 ..                 ...               ...
 145                5.2               2.3
 146                5.0               1.9
 147                5.2               2.0
 148                5.4               2.3
 149                5.1               1.8

 [150 rows x 2 columns],
      target
 0         0
 1         0
 2         0
 3         0
 4         0
 ..      ...
 145       2
 146       2
 147       2
 148       2
 149       2

 [150 rows x 1 columns])

创建#

水平DataFrame#

创建一个由水平切分数据组成的DataFrame。

💡原始数据仍然保持在数据拥有方本地,并不会出域。

作为演示,我们选择了安全聚合和spu安全比较。您可以参考 安全聚合 了解更多安全聚合方案,并选择适合您的安全策略。

[7]:
from secretflow.data.horizontal import read_csv as h_read_csv
from secretflow.security.aggregation import SecureAggregator
from secretflow.security.compare import SPUComparator

# The aggregator and comparator are respectively used to aggregate
# or compare data in subsequent data analysis operations.
aggr = SecureAggregator(device=alice, participants=[alice, bob, carol])

spu = sf.SPU(sf.utils.testing.cluster_def(parties=['alice', 'bob', 'carol']))
comp = SPUComparator(spu)
hdf = h_read_csv({alice: h_alice_path, bob: h_bob_path, carol: h_carol_path},
                 aggregator=aggr,
                 comparator=comp)

垂直DataFrame#

创建一个由水平切分数据组成的DataFrame。

💡原始数据仍然保持在数据拥有方本地,并不会出域。

[8]:
from secretflow.data.vertical import read_csv as v_read_csv

vdf = v_read_csv({alice: v_alice_path, bob: v_bob_path, carol: v_carol_path})

数据分析#

为了保护数据隐私,DataFrame不允许对原始数据进行查看。DataFrame提供了类似pandas的接口来方便用户分析数据。这些接口对水平和垂直切分数据都通用。

在以下操作中,原始数据仍然保持在数据拥有方本地,并不会传输出域。

[9]:
hdf.columns
[9]:
Index(['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)',
       'petal width (cm)', 'target'],
      dtype='object')
[10]:
vdf.columns
[10]:
Index(['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)',
       'petal width (cm)', 'target'],
      dtype='object')

获取最小值,可以看到和原始数据一致。

[11]:
print('Horizontal df:\n', hdf.min())
print('\nVertical df:\n', vdf.min())
print('\nPandas:\n', data.min())
Horizontal df:
 sepal length (cm)    4.3
sepal width (cm)     2.0
petal length (cm)    1.0
petal width (cm)     0.1
target               0.0
dtype: float64

Vertical df:
 sepal length (cm)    4.3
sepal width (cm)     2.0
petal length (cm)    1.0
petal width (cm)     0.1
target               0.0
dtype: float64

Pandas:
 sepal length (cm)    4.3
sepal width (cm)     2.0
petal length (cm)    1.0
petal width (cm)     0.1
target               0.0
dtype: float64

您也可以查看比如最大值、平均值、数量等信息。

[12]:
hdf.max()
[12]:
sepal length (cm)    7.9
sepal width (cm)     4.4
petal length (cm)    6.9
petal width (cm)     2.5
target               2.0
dtype: float64
[13]:
vdf.max()
[13]:
sepal length (cm)    7.9
sepal width (cm)     4.4
petal length (cm)    6.9
petal width (cm)     2.5
target               2.0
dtype: float64
[14]:
hdf.mean(numeric_only=True)
[14]:
sepal length (cm)    5.843333
sepal width (cm)     3.057333
petal length (cm)    3.758000
petal width (cm)     1.199333
target               1.000000
dtype: float64
[15]:
vdf.mean(numeric_only=True)
[15]:
sepal length (cm)    5.843333
sepal width (cm)     3.057333
petal length (cm)    3.758000
petal width (cm)     1.199333
target               1.000000
dtype: float64
[16]:
hdf.count()
[16]:
sepal length (cm)    150
sepal width (cm)     150
petal length (cm)    150
petal width (cm)     150
target               150
dtype: int64
[17]:
vdf.count()
[17]:
sepal length (cm)    150
sepal width (cm)     150
petal length (cm)    150
petal width (cm)     150
target               150
dtype: int64

选取数据#

选取部分列。

[18]:
hdf_part = hdf[['sepal length (cm)', 'target']]
hdf_part.mean(numeric_only=True)
[18]:
sepal length (cm)    5.843333
target               1.000000
dtype: float64
[19]:
vdf_part = hdf[['sepal width (cm)', 'target']]
vdf_part.mean(numeric_only=True)
[19]:
sepal width (cm)    3.057333
target              1.000000
dtype: float64

修改#

水平DataFrame

[20]:
hdf_copy = hdf.copy()
print('Min of target: ', hdf_copy['target'].min()[0])
print('Max of target: ', hdf_copy['target'].max()[0])
Min of target:  0.0
Max of target:  2.0
[21]:
# Set target to 1。
hdf_copy['target'] = 1

# You can see that the value of target has become 1.
print('Min of target: ', hdf_copy['target'].min()[0])
print('Max of target: ', hdf_copy['target'].max()[0])
Min of target:  1.0
Max of target:  1.0

垂直DataFrame

[22]:
vdf_copy = vdf.copy()
print('Min of sepal width (cm): ', vdf_copy['sepal width (cm)'].min()[0])
print('Max of sepal width (cm): ', vdf_copy['sepal width (cm)'].max()[0])
Min of sepal width (cm):  2.0
Max of sepal width (cm):  4.4
[23]:
# Set sepal width (cm) to 20。
vdf_copy['sepal width (cm)'] = 20

# You can see that the value of sepal width (cm) has become 20.
print('Min of sepal width (cm): ', vdf_copy['sepal width (cm)'].min()[0])
print('Max of sepal width (cm): ', vdf_copy['sepal width (cm)'].max()[0])
Min of sepal width (cm):  20
Max of sepal width (cm):  20

收尾#

[24]:
# Clean up temporary files

import shutil

shutil.rmtree(temp_dir, ignore_errors=True)

下一步#

跟着教程 预处理 学习如何对数据进行预处理。