【问题标题】:Randomly concat data frames by row按行随机连接数据帧
【发布时间】:2016-07-22 05:59:35
【问题描述】:

如何按行随机合并、连接或连接 pandas 数据帧?假设我有四个类似这样的数据框(有更多行):

df1 = pd.DataFrame({'col1':["1_1", "1_1"], 'col2':["1_2", "1_2"], 'col3':["1_3", "1_3"]})
df2 = pd.DataFrame({'col1':["2_1", "2_1"], 'col2':["2_2", "2_2"], 'col3':["2_3", "2_3"]})
df3 = pd.DataFrame({'col1':["3_1", "3_1"], 'col2':["3_2", "3_2"], 'col3':["3_3", "3_3"]})
df4 = pd.DataFrame({'col1':["4_1", "4_1"], 'col2':["4_2", "4_2"], 'col3':["4_3", "4_3"]})

我怎样才能加入这四个数据框随机输出这样的东西(它们是随机合并的行):

  col1 col2 col3 col1 col2 col3 col1 col2 col3 col1 col2 col3
0  1_1  1_2  1_3  4_1  4_2  4_3  2_1  2_2  2_3  3_1  3_2  3_3
1  2_1  2_2  2_3  1_1  1_2  1_3  3_1  3_2  3_3  4_1  4_2  4_3

我在想我可以做这样的事情:

my_list = [df1,df2,df3,df4]
my_list = random.sample(my_list, len(my_list))
df = pd.DataFrame({'empty' : []})

for row in df:
    new_df = pd.concat(my_list, axis=1)

print new_df

for 上方的语句仅适用于第一行,之后的每一行(我有更多)都是一样的,即它只会洗牌一次:

  col1 col2 col3 col1 col2 col3 col1 col2 col3 col1 col2 col3
0  4_1  4_2  4_3  1_1  1_2  1_3  2_1  2_2  2_3  3_1  3_2  3_3
1  4_1  4_2  4_3  1_1  1_2  1_3  2_1  2_2  2_3  3_1  3_2  3_3

【问题讨论】:

  • 所以你不在乎列的一致性?
  • @MaxU 不,真的不在乎列的名称,可能是 1,2,3,...,n 或其他东西
  • 我在询问一列中的值...在您想要的 DF 中,第一个 col1 混合了来自不同列的值 - 这就是您想要的吗?
  • 是的,确切地说,重要的是所有 1_i 排成一排,所有 2_i 排成一排,依此类推,但以随机顺序排列。因此,这将混合您所说的值,这是预期的,感谢您清除它。

标签: python numpy pandas


【解决方案1】:

也许是这样的?

import random
import numpy as np

dfs = [df1, df2, df3, df4]
n = np.sum(len(df.columns) for df in dfs)
pd.concat(dfs, axis=1).iloc[:, random.sample(range(n), n)]

Out[130]: 
  col1 col3 col1 col2 col1 col1 col2 col2 col3 col3 col3 col2
0  4_1  4_3  1_1  4_2  2_1  3_1  1_2  3_2  1_3  3_3  2_3  2_2

或者,如果只对 df 进行洗牌,您可以这样做:

dfs = [df1, df2, df3, df4]
random.shuffle(dfs)
pd.concat(dfs, axis=1)

Out[133]: 
  col1 col2 col3 col1 col2 col3 col1 col2 col3 col1 col2 col3
0  4_1  4_2  4_3  2_1  2_2  2_3  1_1  1_2  1_3  3_1  3_2  3_3

【讨论】:

  • 更多pythonic是的,第二个解决方案是我所追求的,但是,这与我的解决方案相似,但它只适用于一行。如果我有 1000 行并且希望每一行都被打乱怎么办?更新的问题。 (毕竟我的解决方案不对)
  • 您能否发布一个多行示例,因为我无法理解您的确切意思。
【解决方案2】:

更新:来自@Divakar 的更好的解决方案:

df1 = pd.DataFrame({'col1':["1_1", "1_1"], 'col2':["1_2", "1_2"], 'col3':["1_3", "1_3"], 'col4':["1_4", "1_4"]})
df2 = pd.DataFrame({'col1':["2_1", "2_1"], 'col2':["2_2", "2_2"], 'col3':["2_3", "2_3"], 'col4':["2_4", "2_4"]})
df3 = pd.DataFrame({'col1':["3_1", "3_1"], 'col2':["3_2", "3_2"], 'col3':["3_3", "3_3"], 'col4':["3_4", "3_4"]})
df4 = pd.DataFrame({'col1':["4_1", "4_1"], 'col2':["4_2", "4_2"], 'col3':["4_3", "4_3"], 'col4':["4_4", "4_4"]})

dfs = [df1, df2, df3, df4]
n = len(dfs)
nrows = dfs[0].shape[0]
ncols = dfs[0].shape[1]
A = pd.concat(dfs, axis=1).values.reshape(nrows,-1,ncols)
sidx = np.random.rand(nrows,n).argsort(1)
out_arr = A[np.arange(nrows)[:,None],sidx,:].reshape(nrows,-1)
df = pd.DataFrame(out_arr)

输出:

In [203]: df
Out[203]:
    0    1    2    3    4    5    6    7    8    9    10   11   12   13   14   15
0  3_1  3_2  3_3  3_4  1_1  1_2  1_3  1_4  4_1  4_2  4_3  4_4  2_1  2_2  2_3  2_4
1  4_1  4_2  4_3  4_4  2_1  2_2  2_3  2_4  3_1  3_2  3_3  3_4  1_1  1_2  1_3  1_4

解释:(c) 迪瓦卡

基于 NumPy 的解决方案

让我们有一个基于 NumPy 的矢量化解决方案,希望是一个快速的解决方案!

1) 让我们将连接值数组重塑为3D 数组,将每一行“切割”成ncols 组,对应于每个输入数据帧中的列数-

A = pd.concat(dfs, axis=1).values.reshape(nrows,-1,ncols)

2) 接下来,我们欺骗 np.aragsort 为我们提供从 0 到 N-1 的随机唯一索引,其中 N 是输入数据帧的数量 -

sidx = np.random.rand(nrows,n).argsort(1)

3) 最后的技巧是 NumPy 的花哨索引以及一些广播以索引到 Asidx 给我们输出数组 -

out_arr = A[np.arange(nrows)[:,None],sidx,:].reshape(nrows,-1)

4) 如果需要,转换为数据框 -

df = pd.DataFrame(out_arr)

旧答案:

IIUC 你可以这样做:

dfs = [df1, df2, df3, df4]
n = len(dfs)
ncols = dfs[0].shape[1]
v = pd.concat(dfs, axis=1).values
a = np.arange(n * ncols).reshape(n, df1.shape[1])

df = pd.DataFrame(np.asarray([v[i, a[random.sample(range(n), n)].reshape(n * ncols,)] for i in dfs[0].index]))

输出

In [150]: df
Out[150]:
    0    1    2    3    4    5    6    7    8    9    10   11
0  1_1  1_2  1_3  3_1  3_2  3_3  4_1  4_2  4_3  2_1  2_2  2_3
1  2_1  2_2  2_3  1_1  1_2  1_3  3_1  3_2  3_3  4_1  4_2  4_3

解释:

In [151]: v
Out[151]:
array([['1_1', '1_2', '1_3', '2_1', '2_2', '2_3', '3_1', '3_2', '3_3', '4_1', '4_2', '4_3'],
       ['1_1', '1_2', '1_3', '2_1', '2_2', '2_3', '3_1', '3_2', '3_3', '4_1', '4_2', '4_3']], dtype=object)

In [152]: a
Out[152]:
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6,  7,  8],
       [ 9, 10, 11]])

【讨论】:

  • 很好,但是,这仅在我有两行时才有效,假设我有 1000 行并且每个 df 包含让我们说 30 列? a 一定是别的东西?
  • 尝试了四个数据帧,每个数据帧有 10000 行和 30 列,它将生成一个新的 df,它有 10000 行和 12 列,并且只有来自 df1 的值。也许我错过了什么?
  • @DracoMalfago,你能再检查一下吗?
  • 哈哈大师!?这责任太大了! :) 让我看看,如果我能帮忙的话。
  • @DracoMalfago 在这种情况下,NumPy 主要是一个矢量化解决方案。 NumPy 或 pandas 是否会比其他更快,没有硬性规定。但根据我几周的 pandas 经验,这是一个非常普遍的观察结果 - 如果您使用的是常规大小(没有 Nulls/NaN)的数字数据,请考虑使用 NumPy。
猜你喜欢
  • 2013-03-03
  • 2017-09-13
  • 2022-08-14
  • 2022-01-22
  • 2017-01-23
  • 2015-02-11
  • 2023-04-02
  • 2017-03-10
相关资源
最近更新 更多