当函数应用于行时,pandas的.groupby函数存在奇怪的问题

时间:2014-01-07 22:36:07

标签: python numpy pandas scipy

我有一组4203x37的CSV数据,我将其重新整形为50436x4,以便找到每组时间步记录的12组3D点之间的欧几里德距离。这对我的实际数据不起作用,但奇怪的是,当我使用随机数重新创建数据时,代码如下......

以下是我的实际数据的代码,这是无效的代码。

df_f_2_norm = df_f.loc[:,'Time':'label37'] # Select columns
N = 12 # Nr of points

# Drop label1 column for later use
df_f_2_norm_time = df_f_2_norm['Time']
df_f_2_norm = df_f_2_norm.drop('Time',1)

# Get shape of data frame
shp = df_f_2_norm.shape

# Use numpy.reshape to reshape the underlying data in the DataFrame
df_f_2_norm = pd.DataFrame(df_f_2_norm.values.reshape(-1,3),columns=list('XYZ'))
df_f_2_norm["Time"] = np.repeat(np.array(df_f_2_norm_time), N) # Number of points per time-label: 12

# Find the Euclidean distance (2-norm)
N_lim = int(0.5*N*(N-1)) 
result_index = ['D{}'.format(tag) for tag in range(1,N_lim+1)] # Column labels
two_norm = df_f_2_norm.groupby('Time')[["X", "Y", "Z"]].apply(lambda g: pd.Series(pdist(g), index=result_index))

现在,如果我们查看two_norm的形状,它应该具有4203x66的形状,即12个点的66欧几里德距离,每个时间戳有4203,每行一个。

实际答案实际上是什么:AssertionError: Index length did not match values - 所以它不喜欢我给它的列标签。好的,如果我们删除标签而只是改为

two_norm = df_f_2_norm.groupby('Time')[["X", "Y", "Z"]].apply(lambda g: pd.Series(pdist(g))

然后我们得到print two_norm.shape的形状((8307846,)) - 我不太明白这里发生了什么,但看起来它甚至没有将所有结果叠加在一起。

虽然它变得更好,因为以下代码在行1140之前一直有效,所以如果我们让

df_f_2_norm = df_f_2_norm[:1140]

然后我们得到以下形状:(95,66)

在此之前哪个是正确的,但如果我们这样做

df_f_2_norm = df_f_2_norm[:1152]

而是提供:(6480,)

所以某些东西显然已经变成了梨形,但如果我们真的看到这一点周围的数据,似乎没什么奇怪的。

             X         Y        Z   Time
1127  -614.770   207.624  120.859  2.533
1128   791.318   291.591   64.160  2.550
1129   728.892   283.473 -207.306  2.550
1130   939.871   251.387 -145.103  2.550
1131   702.987   287.165  398.151  2.550
1132   480.309   285.745  590.925  2.550
1133   723.493   248.699  607.543  2.550
1134   255.664   183.618 -108.176  2.550
1135   -90.333   196.879 -261.102  2.550
1136  -442.132   236.314 -419.216  2.550
1137   133.428   216.805  242.896  2.550
1138  -242.201   192.100  191.588  2.550
1139  -616.844   210.060  123.202  2.550
1140  -655.054  1390.084 -359.369  1.100
1141  -726.517  1222.015 -590.799  1.100
1142  -671.655  1146.959 -797.080  1.100
1143  -762.048  1379.722    8.505  1.100
1144  -981.748  1169.959   72.773  1.100
1145 -1011.853   968.364  229.070  1.100
1146  -778.290   827.571 -370.463  1.100
1147  -761.608   460.835 -329.487  1.100
1148  -815.330    77.501 -314.721  1.100
1149  -925.764   831.944  -34.206  1.100
1150 -1009.297   475.362  -73.077  1.100
1151 -1193.310   139.839 -142.666  1.100
1152  -631.630  1388.573 -353.642  1.117
1153  -697.771  1234.274 -593.501  1.117

所以这很奇怪。所以我试着用随机数字来复制这个问题,但这一切都很完美,甚至标签都没有意义......

import numpy as np
import pandas as pd
import string
from scipy.spatial.distance import pdist, squareform
# Computes the distance between m points using Euclidean distance (2-norm)
# as the distance metric between the points. The points are arranged as m 
# n-dimensional row vectors in the matrix X.

# Test data frame
N = 12 # Nr of points
col_ids = string.letters[:N]
df = pd.DataFrame(
      np.random.randn(4203, 3*N+1), 
      columns=['Time']+['{}_{}'.format(letter, coord) for letter in col_ids for coord in list('xyz')])

# Drop time column for later use
df_time = df['Time']
df = df.drop('Time',1)

print df.shape

# Use numpy.reshape to reshape the underlying data in the DataFrame
df = pd.DataFrame(df.values.reshape(-1,3), columns=list('XYZ'))
df["Time"] = np.repeat(np.array(df_time), N)

print df.shape

# Find the Euclidean distance (2-norm)
N_lim = int(0.5*N*(N-1))
result_index = ['D{}'.format(coord) for coord in range(1,N_lim+1)]
two_norm = df.groupby('Time')[["X", "Y", "Z"]].apply(lambda g: pd.Series(pdist(g), index=result_index))

print two_norm.shape

哪个有输出(来自三个打印语句)

(4203, 36)
(50436, 4)
(4203, 66)

正如您所看到的,最终结果的形状完全如此。但是在这两组数据之间确实没有什么不同(据我所知),这些数字差异不会对结果数据帧的实际形状产生任何影响。

我错过了什么?

感谢。


可在此处找到原始数据(本文第一部分中使用的数据):https://www.dropbox.com/sh/80f8ue4ffa4067t/Pntl5-gUW4

应该注意的是,在dropbox中找到的.csv文件是数据框df_f_2_norm - 因此它不是原始数据,而是重新整形的版本(所以上面的第一行代码,不需要执行以达到此状态,因为它已经执行过。)

1 个答案:

答案 0 :(得分:1)

如果您运行以下代码

df_f_2_norm.Time.value_counts()

然后你可以发现并非所有时间值都有12行。

这是输出:

1.333    492
1.383    492
1.317    492
1.400    492
1.467    492
1.450    492
1.483    492
1.417    492
1.500    492
1.367    492
1.350    492
1.433    492
1.533    480
1.517    480
1.550    468
...
4.800    12
4.600    12
4.750    12
4.833    12
4.667    12
4.700    12
4.650    12
4.683    12
4.633    12
4.617    12
4.817    12
4.583    12
4.733    12
4.767    12
4.783    12
Length: 272, dtype: int64

如果要每12行对数据框进行分组,您可以:

import pandas as pd
from scipy.spatial.distance import pdist, squareform

df_f_2_norm = pd.read_csv("astrid_data.csv")
g = np.repeat(np.arange(df_f_2_norm.shape[0]//12), 12)

N = 12

N_lim = int(0.5*N*(N-1)) 
result_index = ['D{}'.format(tag) for tag in range(1,N_lim+1)] # Column labels
two_norm = df_f_2_norm.groupby(g)[["X", "Y", "Z"]].apply(lambda g: pd.Series(pdist(g), index=result_index))